main.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. # -*- coding: utf-8 -*-
  2. from openerp import http
  3. from openerp.http import request
  4. from werkzeug.wrappers import Response
  5. from werkzeug.datastructures import Headers
  6. from datetime import datetime
  7. from dateutil.relativedelta import relativedelta as rd
  8. from dateutil.parser import parse
  9. from gzip import GzipFile
  10. from StringIO import StringIO as IO
  11. import simplejson as json
  12. import gzip
  13. import logging
  14. LOGGER = logging.getLogger(__name__)
  15. DATE_FORMAT = '%Y-%m-%d'
  16. GZIP_COMPRESSION_LEVEL = 9
  17. '''
  18. ___ ___ __ __ __ ___ __ __ ___ __ ___ __ __ __ __ __
  19. |__| | | |__) / ` / \ |\ | | |__) / \ | | |__ |__) |__ / \ |__) |__) / \ /__`
  20. | | | | | \__, \__/ | \| | | \ \__/ |___ |___ |___ | \ | \__/ | \ | \__/ .__/
  21. # Resource paths
  22. - /init: return json response gzip compressed contains values for sale operation
  23. - /create_product: create product on the fly POS and return it
  24. - /create_customer: create customer on the fly and return it
  25. - /process_sale: processing sale and return true if completed
  26. '''
  27. class PosSales(http.Controller):
  28. '''
  29. Get server date
  30. '''
  31. def get_server_date(self):
  32. return datetime.now().strftime(DATE_FORMAT)
  33. '''
  34. Get current user information
  35. '''
  36. def get_user(self):
  37. user = request.env.user
  38. return {
  39. 'id': user.id,
  40. 'name': user.name,
  41. 'displayName': user.display_name,
  42. 'currency': {
  43. 'id': user.company_id.currency_id.id,
  44. 'name': user.company_id.currency_id.name,
  45. 'displayName': user.company_id.currency_id.display_name,
  46. 'symbol': user.company_id.currency_id.symbol
  47. },
  48. 'company': {
  49. 'id': user.company_id.id,
  50. 'name': user.company_id.name,
  51. 'displayName': user.company_id.display_name
  52. }
  53. }
  54. '''
  55. Get currencies
  56. '''
  57. def get_currencies(self):
  58. return [{
  59. 'id': currency.id,
  60. 'name': currency.name,
  61. 'displayName': currency.display_name,
  62. 'base': currency.base,
  63. 'accuracy': currency.accuracy,
  64. 'rateSilent': currency.rate_silent,
  65. 'rounding': currency.rounding,
  66. 'symbol': currency.symbol,
  67. 'position': currency.position,
  68. 'decimalSeparator': currency.decimal_separator,
  69. 'decimalPlaces': currency.decimal_places,
  70. 'thousandsSeparator': currency.thousands_separator
  71. } for currency in request.env['res.currency'].search([('active', '=', True)])]
  72. '''
  73. Get all active journals
  74. '''
  75. def get_journals(self):
  76. return [{
  77. 'id': journal.id,
  78. 'name': journal.name,
  79. 'displayName': journal.display_name,
  80. 'code': journal.code,
  81. 'cashControl': journal.cash_control,
  82. 'type': journal.type,
  83. 'currency': {
  84. 'id': journal.currency.id,
  85. 'name': journal.currency.name,
  86. 'displayName': journal.currency.display_name
  87. },
  88. 'defaultCreditAccount': {
  89. 'id': journal.default_credit_account_id.id,
  90. 'name': journal.default_credit_account_id.name,
  91. 'displayName': journal.default_credit_account_id.display_name,
  92. 'code': journal.default_credit_account_id.code,
  93. 'exchangeRate': journal.default_credit_account_id.exchange_rate,
  94. 'foreignBalance': journal.default_credit_account_id.foreign_balance,
  95. 'reconcile': journal.default_credit_account_id.reconcile,
  96. 'debit': journal.default_credit_account_id.debit,
  97. 'credit': journal.default_credit_account_id.credit,
  98. 'currencyMode': journal.default_credit_account_id.currency_mode,
  99. 'companyCurrency': {
  100. 'id': journal.default_credit_account_id.company_currency_id.id,
  101. 'name': journal.default_credit_account_id.company_currency_id.name,
  102. 'displayName': journal.default_credit_account_id.company_currency_id.display_name,
  103. },
  104. 'currency': {
  105. 'id': journal.default_credit_account_id.currency_id.id,
  106. 'name': journal.default_credit_account_id.currency_id.name,
  107. 'displayName': journal.default_credit_account_id.currency_id.display_name
  108. },
  109. }
  110. } for journal in request.env['account.journal'].search([('type', 'in', ['bank', 'cash']), ('default_credit_account_id.currency_id', '=', False), ('active', '=', True)], order='id')]
  111. '''
  112. Get all active customers
  113. '''
  114. def get_customers(self):
  115. return [{
  116. 'id': customer.id,
  117. 'name': customer.name,
  118. 'displayName': customer.display_name,
  119. 'imageMedium': customer.image_medium,
  120. 'phone': customer.phone,
  121. 'mobile': customer.mobile,
  122. 'email': customer.email
  123. } for customer in request.env['res.partner'].search([('customer', '=', True), ('active', '=', True)])]
  124. '''
  125. Get all saleable and active products
  126. '''
  127. def get_products(self):
  128. return [{
  129. 'id': product.id,
  130. 'name': product.name,
  131. 'displayName': product.display_name,
  132. 'ean13': product.ean13,
  133. 'defaultCode': product.default_code,
  134. 'imageMedium': product.image_medium,
  135. 'listPrice': product.list_price,
  136. 'variantCount': product.product_variant_count,
  137. 'quantity': 1,
  138. 'price': product.list_price,
  139. 'minimumPrice': product.minimum_price,
  140. 'maximumPrice': product.maximum_price,
  141. 'discount': 0,
  142. 'variants': [{
  143. 'id': variant.id,
  144. 'name': variant.name,
  145. 'displayName': variant.display_name,
  146. 'ean13': variant.ean13,
  147. 'defaultCode': product.default_code,
  148. 'imageMedium': variant.image_medium,
  149. 'listPrice': variant.list_price,
  150. 'quantity': 1,
  151. 'price': variant.list_price,
  152. 'minimumPrice': product.minimum_price,
  153. 'maximumPrice': product.maximum_price,
  154. 'discount': 0,
  155. } for variant in product.product_variant_ids if variant.active]
  156. } for product in request.env['product.template'].search([('sale_ok', '=', True), ('list_price', '>', 0), ('active', '=', True)])]
  157. '''
  158. Get all active payment terms
  159. '''
  160. def get_payment_terms(self):
  161. return [{
  162. 'id': payment_term.id,
  163. 'name': payment_term.name,
  164. 'displayName': payment_term.display_name,
  165. 'lines': [{
  166. 'id': line.id,
  167. 'days': line.days,
  168. 'days2': line.days2,
  169. 'value': line.value,
  170. 'valueAmount': line.value_amount
  171. } for line in payment_term.line_ids]
  172. } for payment_term in request.env['account.payment.term'].search([('active', '=', True)])]
  173. '''
  174. Make JSON response
  175. '''
  176. def make_json_response(self, data=None, status=200):
  177. return Response(json.dumps(data), status=status, content_type='application/json')
  178. '''
  179. Make GZIP to JSON response
  180. '''
  181. def make_gzip_response(self, data=None, status=200):
  182. gzip_buffer = IO()
  183. with GzipFile(mode='wb', compresslevel=GZIP_COMPRESSION_LEVEL, fileobj=gzip_buffer) as gzip_file:
  184. gzip_file.write(json.dumps(data))
  185. contents = gzip_buffer.getvalue()
  186. gzip_buffer.close()
  187. headers = Headers()
  188. headers.add('Content-Encoding', 'gzip')
  189. headers.add('Vary', 'Accept-Encoding')
  190. headers.add('Content-Length', len(contents))
  191. return Response(contents, status=status, headers=headers, content_type='application/json')
  192. '''
  193. '''
  194. def make_info_log(self, log):
  195. LOGGER.info(log)
  196. '''
  197. New purchase resource route
  198. '''
  199. @http.route('/eiru_sales/init', auth='user', methods=['GET'], cors='*')
  200. def init_sale(self, **kw):
  201. self.make_info_log('Sending JSON response')
  202. return self.make_gzip_response({
  203. 'date': self.get_server_date(),
  204. 'user': self.get_user(),
  205. 'currencies': self.get_currencies(),
  206. 'journals': self.get_journals(),
  207. 'customers': self.get_customers(),
  208. 'products': self.get_products(),
  209. 'paymentTerms': self.get_payment_terms()
  210. })
  211. '''
  212. Create customer and return data
  213. '''
  214. @http.route('/eiru_sales/create_customer', type='json', auth='user', methods=['POST'], cors='*')
  215. def create_customer(self, **kw):
  216. self.make_info_log('Creating customer')
  217. customer = request.env['res.partner'].create({
  218. 'name': kw.get('name'),
  219. 'ruc': kw.get('ruc'),
  220. 'phone': kw.get('phone'),
  221. 'customer': True
  222. })
  223. return {
  224. 'id': customer.id,
  225. 'name': customer.name,
  226. 'displayName': customer.display_name,
  227. 'imageMedium': customer.image_medium,
  228. 'phone': customer.phone,
  229. 'mobile': customer.mobile,
  230. 'email': customer.email
  231. }
  232. '''
  233. Create product and return data
  234. '''
  235. @http.route('/eiru_sales/create_product', type='json', auth='user', methods=['POST'], cors='*')
  236. def create_product(self, **kw):
  237. self.make_info_log('Creating customer')
  238. product = request.env['product.template'].create({
  239. 'name': kw.get('name'),
  240. 'list_price': float(kw.get('price')),
  241. 'ean13': kw.get('ean13')
  242. })
  243. return {
  244. 'id': product.id,
  245. 'name': product.name,
  246. 'displayName': product.display_name,
  247. 'ean13': product.ean13,
  248. 'imageMedium': product.image_medium,
  249. 'listPrice': product.list_price,
  250. 'variantCount': product.product_variant_count,
  251. 'quantity': 1,
  252. 'price': product.list_price,
  253. 'discount': 0,
  254. 'variants': [{
  255. 'id': variant.id,
  256. 'name': variant.name,
  257. 'displayName': variant.display_name,
  258. 'ean13': variant.ean13,
  259. 'imageMedium': variant.image_medium,
  260. 'listPrice': variant.list_price,
  261. 'quantity': 1,
  262. 'price': variant.list_price,
  263. 'discount': 0,
  264. } for variant in product.product_variant_ids if variant.active]
  265. }
  266. '''
  267. Get currency from journal
  268. '''
  269. def get_currency(self, journal_id):
  270. journal = request.env['account.journal'].browse(journal_id)
  271. return journal.default_credit_account_id.currency_id.id or journal.default_credit_account_id.company_currency_id.id
  272. '''
  273. Check currency in pricelist and get it
  274. '''
  275. def get_pricelist(self, currency_id):
  276. pricelist = request.env['product.pricelist'].search([('active', '=', True), ('type', '=', 'sale')])
  277. if not True in pricelist.mapped(lambda p: p.currency_id.id == currency_id):
  278. pricelist = pricelist[0].copy()
  279. pricelist.write({
  280. 'currency_id': currency_id
  281. })
  282. else:
  283. pricelist = pricelist.filtered(lambda p: p.currency_id.id == currency_id)
  284. return pricelist
  285. '''
  286. Create sale order from cart items values
  287. '''
  288. def create_sale_from_cart(self, partner_id, cart_items, date_confirm, currency_id, pricelist_id, payment_term_id=None):
  289. return request.env['sale.order'].create({
  290. 'partner_id': partner_id,
  291. 'order_line': [[0, False, {
  292. 'product_id': int(line.get('id')),
  293. 'product_uom_qty': float(line.get('quantity')),
  294. 'price_unit': float(line.get('price'))
  295. }] for line in cart_items],
  296. 'picking_policy': 'direct',
  297. 'date_confirm': date_confirm,
  298. 'currency_id': currency_id,
  299. 'pricelist_id': pricelist_id,
  300. 'payment_term': payment_term_id,
  301. 'state': 'draft',
  302. })
  303. '''
  304. Confirm sale order
  305. '''
  306. def confirm_sale_order(self, sale_order_id):
  307. sale_order = request.env['sale.order'].browse(sale_order_id)
  308. sale_order.write({
  309. 'state': 'manual'
  310. })
  311. return sale_order.action_button_confirm()
  312. '''
  313. Create invoice from sale order
  314. '''
  315. def create_invoice(self, sale_order_id, currency_id, date_today):
  316. sale_order = request.env['sale.order'].browse(sale_order_id)
  317. invoice_id = sale_order.action_invoice_create()
  318. invoice = request.env['account.invoice'].browse(invoice_id)
  319. date_due = parse(date_today) + rd(days=max(invoice.payment_term.line_ids.mapped(lambda x: x.days + x.days2)))
  320. invoice.write({
  321. 'currency_id': currency_id,
  322. 'date_invoice': date_today,
  323. 'date_due': date_due.strftime(DATE_FORMAT),
  324. 'state': 'open'
  325. })
  326. return invoice
  327. '''
  328. Create move lines
  329. '''
  330. def create_invoice_move_lines(self, invoice_id, paid_amount, date_today):
  331. invoice = request.env['account.invoice'].browse(invoice_id)
  332. invoice_move_lines = invoice._get_analytic_lines()
  333. decimal_precision = request.env['decimal.precision'].precision_get('Account')
  334. compute_taxes = request.env['account.invoice.tax'].compute(invoice)
  335. invoice.check_tax_lines(compute_taxes)
  336. invoice._recompute_tax_amount()
  337. invoice_move_lines += request.env['account.invoice.tax'].move_line_get(invoice.id)
  338. total, total_currency, invoice_move_lines = invoice.compute_invoice_totals(invoice.company_id.currency_id, invoice.reference, invoice_move_lines)
  339. paid_percentage = paid_amount / round(total, decimal_precision)
  340. distributed_percentage = -(paid_percentage / len(invoice.payment_term.line_ids))
  341. payment_lines = []
  342. for line in invoice.payment_term.line_ids:
  343. date_due = (parse(date_today) + rd(days=line.days + line.days2)).strftime(DATE_FORMAT)
  344. if paid_percentage and paid_percentage < 1.0:
  345. payment_lines.append([date_today, paid_percentage])
  346. paid_percentage = paid_amount = 0
  347. if date_due == date_today and line.value_amount:
  348. distributed_percentage = -((payment_lines[0][1] - line.value_amount) / (len(invoice.payment_term.line_ids) - 1))
  349. continue
  350. if line.value != 'balance':
  351. payment_lines.append([date_due, line.value_amount + distributed_percentage])
  352. continue
  353. payment_lines.append([date_due, line.value_amount])
  354. for payment_line in payment_lines:
  355. current_price = round(total * payment_line[1], decimal_precision)
  356. if current_price < 0.0:
  357. continue
  358. paid_amount += current_price
  359. invoice_move_lines.append({
  360. 'type': 'dest',
  361. 'name': '/',
  362. 'price': current_price if payment_line[1] else round(total - paid_amount, decimal_precision) or total,
  363. 'account_id': invoice.account_id.id,
  364. 'date_maturity': payment_line[0],
  365. 'amount_currency': invoice.company_id.currency_id.compute(payment_line[1], invoice.currency_id) if invoice.currency_id != invoice.company_id.currency_id else False,
  366. 'currency_id': invoice.currency_id != invoice.company_id.currency_id and invoice.currency_id.id,
  367. 'ref': invoice.reference
  368. })
  369. payment_lines = []
  370. return invoice_move_lines
  371. '''
  372. Create account move
  373. '''
  374. def create_account_move(self, invoice_id, invoice_move_lines):
  375. invoice = request.env['account.invoice'].browse(invoice_id)
  376. accounting_partner = request.env['res.partner']._find_accounting_partner(invoice.partner_id)
  377. move_line_values = [(0, 0, invoice.line_get_convert(line, accounting_partner.id, invoice.date_invoice)) for line in invoice_move_lines]
  378. move_line_values = invoice.group_lines(invoice_move_lines, move_line_values)
  379. move_line_values = invoice.finalize_invoice_move_lines(move_line_values)
  380. ctx = dict(request.context, lang=invoice.partner_id.lang, company_id=invoice.company_id.id)
  381. period = invoice.period_id
  382. if not period:
  383. period = period.with_context(ctx).find(invoice.date_invoice)[:1]
  384. if period:
  385. for line in move_line_values:
  386. line[2]['period_id'] = period.id
  387. ctx['invoice'] = invoice
  388. ctx_nolang = ctx.copy()
  389. ctx_nolang.pop('lang', None)
  390. account_move = request.env['account.move'].with_context(ctx_nolang).create({
  391. 'ref': invoice.reference or invoice.name,
  392. 'line_id': move_line_values,
  393. 'journal_id': invoice.journal_id.id,
  394. 'date': invoice.date_invoice,
  395. 'narration': invoice.comment,
  396. 'company_id': invoice.company_id.id,
  397. 'period_id': period.id
  398. })
  399. invoice.with_context(ctx).write({
  400. 'move_id': account_move.id,
  401. 'period_id': account_move.period_id.id,
  402. 'move_name': account_move.name,
  403. })
  404. account_move.post()
  405. return account_move
  406. '''
  407. Number to invoice
  408. '''
  409. def number_invoice(self, invoice_id):
  410. request.env['account.invoice'].browse(invoice_id).action_number()
  411. '''
  412. Create voucher
  413. '''
  414. def create_account_voucher(self, account_move_id, journal_id, currency_id, paid_amount):
  415. account_move = request.env['account.move'].browse(account_move_id)
  416. account_journal = request.env['account.journal'].browse(journal_id)
  417. account_voucher = request.env['account.voucher'].create({
  418. 'reference': account_move.name,
  419. 'type': 'receipt',
  420. 'journal_id': account_journal.id,
  421. 'company_id': account_move.company_id.id,
  422. 'pre_line': True,
  423. 'amount': paid_amount,
  424. 'period_id': account_move.period_id.id,
  425. 'date': account_move.date,
  426. 'partner_id': account_move.partner_id.id,
  427. 'account_id': account_journal.default_credit_account_id.id,
  428. 'currency_id': currency_id,
  429. 'line_cr_ids': [[0, False, {
  430. 'date_due': l.date_maturity,
  431. 'account_id': l.account_id.id,
  432. 'date_original': l.invoice.date_invoice,
  433. 'move_line_id': l.id,
  434. 'amount_original': abs(l.credit or l.debit or 0.0),
  435. 'amount_unreconciled': abs(l.amount_residual),
  436. 'amount': abs(l.debit) if account_move.date == l.date_maturity else 0.0,
  437. 'reconcile': account_move.date == l.date_maturity,
  438. 'currency_id': currency_id
  439. }] for l in account_move.line_id]
  440. })
  441. account_voucher.action_move_line_create()
  442. return account_voucher
  443. '''
  444. Close a invoice
  445. '''
  446. def close_invoice(self, invoice_id):
  447. invoice = request.env['account.invoice'].browse(invoice_id)
  448. if invoice.residual == 0:
  449. invoice.write({
  450. 'state': 'paid'
  451. })
  452. '''
  453. Create account bank statement lines
  454. '''
  455. def create_bank_statement_lines(self, account_voucher_id, reference=None):
  456. account_voucher = request.env['account.voucher'].browse(account_voucher_id)
  457. return [[0, False, {
  458. 'name': account_voucher.reference,
  459. 'amount': account_voucher.amount,
  460. 'partner_id': account_voucher.partner_id.id,
  461. 'voucher_id': account_voucher.id,
  462. 'journal_id': account_voucher.journal_id.id,
  463. 'account_id': account_voucher.account_id.id,
  464. 'journal_entry_id': account_voucher.move_id.id,
  465. 'currency_id': account_voucher.currency_id.id,
  466. 'ref': 'POS/' + (reference or '')
  467. }]]
  468. '''
  469. Create account bank statement
  470. '''
  471. def create_bank_statement(self, account_voucher_id, account_bank_statement_lines, date_today):
  472. account_voucher = request.env['account.voucher'].browse(account_voucher_id)
  473. account_bank_statement = request.env['account.bank.statement'].search([('journal_id', '=', account_voucher.journal_id.id), ('date', '=', date_today)])
  474. account_bank_statement_values = {
  475. 'date': date_today,
  476. 'user_id': request.env.user.id,
  477. 'journal_id': account_voucher.journal_id.id,
  478. 'period_id': account_voucher.period_id.id,
  479. 'line_ids': account_bank_statement_lines,
  480. 'state': 'open' if account_voucher.journal_id.type == 'cash' else 'draft'
  481. }
  482. if account_bank_statement:
  483. size = len(account_bank_statement)
  484. if size == 1:
  485. account_bank_statement.write(account_bank_statement_values)
  486. else:
  487. account_bank_statement[size - 1].write(account_bank_statement_values)
  488. else:
  489. account_bank_statement.create(account_bank_statement_values)
  490. return account_bank_statement
  491. '''
  492. Process sale
  493. '''
  494. @http.route('/eiru_sales/process_sale', type='json', auth='user', methods=['POST'], cors='*')
  495. def process_sale(self, **kw):
  496. self.make_info_log('Processing sale...')
  497. # Get date
  498. date_now = datetime.now().strftime(DATE_FORMAT)
  499. self.make_info_log('[OK] Getting date')
  500. # Get currency
  501. currency_id = self.get_currency(kw.get('journalId'))
  502. self.make_info_log('[OK] Getting journal')
  503. # Get Pricelist
  504. pricelist = self.get_pricelist(currency_id)
  505. self.make_info_log('[OK] Getting product pricelist')
  506. # Create sale order
  507. sale_order = self.create_sale_from_cart(kw.get('customerId'), kw.get('items'), date_now, currency_id, pricelist.id, kw.get('paymentTermId'))
  508. self.make_info_log('[OK] Creating sale order')
  509. # Check if budget
  510. if kw.get('mode', 'sale') != 'sale':
  511. return {
  512. 'process': True
  513. }
  514. # Confirm sale
  515. self.confirm_sale_order(sale_order.id)
  516. self.make_info_log('[OK] Confirm sale order')
  517. # Create invoice
  518. invoice = self.create_invoice(sale_order.id, currency_id, date_now)
  519. self.make_info_log('[OK] Creating invoice')
  520. # Create invoice move lines
  521. invoice_move_lines = self.create_invoice_move_lines(invoice.id, float(kw.get('payment')), date_now)
  522. self.make_info_log('[OK] Creating invoice move lines')
  523. # Create account move
  524. account_move = self.create_account_move(invoice.id, invoice_move_lines)
  525. self.make_info_log('[OK] Creating account move')
  526. # Number invoice
  527. self.number_invoice(invoice.id)
  528. self.make_info_log('[OK] Number invoice')
  529. # Create account voucher
  530. account_voucher = self.create_account_voucher(account_move.id, kw.get('journalId'), currency_id, float(kw.get('payment')))
  531. self.make_info_log('[OK] Creating account voucher')
  532. # Close invoice
  533. self.close_invoice(invoice.id)
  534. self.make_info_log('[OK] Closing invoice')
  535. # Create account bank statement lines
  536. account_bank_statement_lines = self.create_bank_statement_lines(account_voucher.id)
  537. self.make_info_log('[OK] Creating account bank statement lines')
  538. # Create bank statement
  539. self.create_bank_statement(account_voucher.id, account_bank_statement_lines, date_now)
  540. self.make_info_log('[OK] Creating account bank statement')
  541. return {
  542. 'process': True
  543. }