main.py 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826
  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 pytz import timezone
  10. from gzip import GzipFile
  11. from StringIO import StringIO as IO
  12. import simplejson as json
  13. import gzip
  14. import logging
  15. LOGGER = logging.getLogger(__name__)
  16. DATE_FORMAT = '%Y-%m-%d'
  17. DATETIME_FORMAT = '%Y-%m-%d %H:%m:%S'
  18. GZIP_COMPRESSION_LEVEL = 9
  19. class Purchases(http.Controller):
  20. '''
  21. Get timezone
  22. '''
  23. def get_timezone(self):
  24. return timezone(request.context['tz'])
  25. '''
  26. Get server date to send
  27. '''
  28. def get_server_date(self):
  29. return datetime.now(self.get_timezone()).strftime(DATE_FORMAT)
  30. '''
  31. Get current user information
  32. '''
  33. def get_user(self):
  34. user = request.env.user
  35. return {
  36. 'id': user.id,
  37. 'name': user.name,
  38. 'displayName': user.display_name,
  39. 'currency': {
  40. 'id': user.company_id.currency_id.id,
  41. 'name': user.company_id.currency_id.name,
  42. 'displayName': user.company_id.currency_id.display_name,
  43. 'symbol': user.company_id.currency_id.symbol
  44. },
  45. 'company': {
  46. 'id': user.company_id.id,
  47. 'name': user.company_id.name,
  48. 'displayName': user.company_id.display_name
  49. }
  50. }
  51. '''
  52. Get currencies
  53. '''
  54. def get_currencies(self):
  55. return [{
  56. 'id': currency.id,
  57. 'name': currency.name,
  58. 'displayName': currency.display_name,
  59. 'base': currency.base,
  60. 'accuracy': currency.accuracy,
  61. 'rateSilent': currency.rate_silent,
  62. 'rounding': currency.rounding,
  63. 'symbol': currency.symbol,
  64. 'position': currency.position,
  65. 'decimalSeparator': currency.decimal_separator,
  66. 'decimalPlaces': currency.decimal_places,
  67. 'thousandsSeparator': currency.thousands_separator
  68. } for currency in request.env['res.currency'].search([('active', '=', True)])]
  69. '''
  70. Get currencies from journals
  71. '''
  72. def get_currencies_from_journal(self):
  73. domain = [
  74. ('type', 'in', ['bank', 'cash']),
  75. ('default_debit_account_id.currency_id', '=', False),
  76. ('active', '=', True)
  77. ]
  78. currencies = []
  79. for j in request.env['account.journal'].search(domain):
  80. c = j.currency or j.company_id.currency_id
  81. currencies.append({
  82. 'id': c.id,
  83. 'name': c.display_name,
  84. 'base': c.base,
  85. 'symbol': c.symbol,
  86. 'position': c.position,
  87. 'rateSilent': c.rate_silent,
  88. 'decimalSeparator': c.decimal_separator,
  89. 'decimalPlaces': c.decimal_places,
  90. 'thousandsSeparator': c.thousands_separator
  91. })
  92. return {c['id']:c for c in currencies}.values()
  93. '''
  94. Get all active journals
  95. '''
  96. def get_journals(self):
  97. return [{
  98. 'id': journal.id,
  99. 'name': journal.name,
  100. 'displayName': journal.display_name,
  101. 'code': journal.code,
  102. 'cashControl': journal.cash_control,
  103. 'type': journal.type,
  104. 'currency': {
  105. 'id': journal.currency.id,
  106. 'name': journal.currency.name,
  107. 'displayName': journal.currency.display_name
  108. },
  109. 'defaultDebitAccount': {
  110. 'id': journal.default_debit_account_id.id,
  111. 'name': journal.default_debit_account_id.name,
  112. 'displayName': journal.default_debit_account_id.display_name,
  113. 'code': journal.default_debit_account_id.code,
  114. 'exchange_rate': journal.default_credit_account_id.exchange_rate,
  115. 'foreignBalance': journal.default_credit_account_id.foreign_balance,
  116. 'reconcile': journal.default_credit_account_id.reconcile,
  117. 'debit': journal.default_credit_account_id.debit,
  118. 'credit': journal.default_credit_account_id.credit,
  119. 'currencyMode': journal.default_credit_account_id.currency_mode,
  120. 'companyCurrency': {
  121. 'id': journal.default_credit_account_id.company_currency_id.id,
  122. 'name': journal.default_credit_account_id.company_currency_id.name,
  123. 'displayName': journal.default_credit_account_id.company_currency_id.display_name,
  124. },
  125. 'currency': {
  126. 'id': journal.default_credit_account_id.currency_id.id,
  127. 'name': journal.default_credit_account_id.currency_id.name,
  128. 'displayName': journal.default_credit_account_id.currency_id.display_name
  129. }
  130. }
  131. } for journal in request.env['account.journal'].search([('type', 'in', ['bank', 'cash']), ('default_debit_account_id.currency_id', '=', False), ('active', '=', True)], order='id')]
  132. '''
  133. Get all active suppliers
  134. '''
  135. def get_suppliers(self):
  136. return [{
  137. 'id': supplier.id,
  138. 'name': supplier.name,
  139. 'displayName': supplier.display_name,
  140. 'imageMedium': supplier.image_medium,
  141. 'ruc': supplier.ruc,
  142. 'phone': supplier.phone,
  143. 'mobile': supplier.mobile,
  144. 'email': supplier.email
  145. } for supplier in request.env['res.partner'].search([('supplier', '=', True), ('active', '=', True)])]
  146. '''
  147. Get all purchasable and active products
  148. '''
  149. def get_products(self, type=None):
  150. product_obj = request.env['product.template']
  151. domain = [('standard_price', '>=', 0), ('active', '=', True)]
  152. if type == 'purchase':
  153. domain.append(('purchase_ok', '=', True))
  154. else:
  155. if product_obj.fields_get('hr_expense_ok'):
  156. domain.append(('hr_expense_ok', '=', True))
  157. else:
  158. return []
  159. return [{
  160. 'id': product.id,
  161. 'name': product.name,
  162. 'displayName': product.display_name,
  163. 'ean13': product.ean13,
  164. 'imageMedium': product.image_medium,
  165. 'standardPrice': product.standard_price,
  166. 'variantCount': product.product_variant_count,
  167. 'quantity': 1,
  168. 'price': product.standard_price,
  169. 'minimumPrice': product.minimum_price,
  170. 'maximumPrice': product.maximum_price,
  171. 'variants': [{
  172. 'id': variant.id,
  173. 'name': variant.name,
  174. 'displayName': variant.display_name,
  175. 'ean13': variant.ean13,
  176. 'imageMedium': variant.image_medium,
  177. 'standardPrice': variant.standard_price,
  178. 'quantity': 1,
  179. 'price': variant.standard_price,
  180. 'minimumPrice': product.minimum_price,
  181. 'maximumPrice': product.maximum_price
  182. } for variant in product.product_variant_ids if variant.active]
  183. } for product in product_obj.search(domain)]
  184. '''
  185. Get all incoming and active picking types
  186. '''
  187. def get_picking_types(self):
  188. return [{
  189. 'id': picking_type.id,
  190. 'name': picking_type.name,
  191. 'displayName': picking_type.display_name
  192. } for picking_type in request.env['stock.picking.type'].search([('code', '=', 'incoming'), ('active', '=', True)])]
  193. '''
  194. Get all active payment terms
  195. '''
  196. def get_payment_terms(self):
  197. return [{
  198. 'id': payment_term.id,
  199. 'name': payment_term.name,
  200. 'displayName': payment_term.display_name,
  201. 'lines': [{
  202. 'id': line.id,
  203. 'days': line.days,
  204. 'days2': line.days2,
  205. 'value': line.value,
  206. 'valueAmount': line.value_amount
  207. } for line in payment_term.line_ids]
  208. } for payment_term in request.env['account.payment.term'].search([('active', '=', True)])]
  209. '''
  210. Get all banks
  211. '''
  212. def get_banks(self):
  213. banks = [
  214. {
  215. 'id': bank.id,
  216. 'name': bank.display_name
  217. } for bank in request.env['res.bank'].search([('active', '=', True)])
  218. ]
  219. return banks
  220. '''
  221. '''
  222. def get_cheque_types(self):
  223. return [
  224. {
  225. 'id': type.id,
  226. 'name': type.display_name,
  227. 'isBank': type.is_bank,
  228. 'isCash': type.is_cash
  229. } for type in request.env['res.bank.cheque.type'].search([])
  230. ]
  231. '''
  232. Get bank payment types
  233. '''
  234. def get_bank_payment_types(self, journal_id=None):
  235. return request.env['res.bank.payments.type'].get_bank_payments_type(journal_id)
  236. '''
  237. Make JSON response to send
  238. '''
  239. def make_response(self, data=None, status=200):
  240. return Response(json.dumps(data), status=status, content_type='application/json')
  241. '''
  242. Make GZIP to JSON response
  243. '''
  244. def make_gzip_response(self, data=None, status=200):
  245. gzip_buffer = IO()
  246. with GzipFile(mode='wb', compresslevel=GZIP_COMPRESSION_LEVEL, fileobj=gzip_buffer) as gzip_file:
  247. gzip_file.write(json.dumps(data))
  248. contents = gzip_buffer.getvalue()
  249. gzip_buffer.close()
  250. headers = Headers()
  251. headers.add('Content-Encoding', 'gzip')
  252. headers.add('Vary', 'Accept-Encoding')
  253. headers.add('Content-Length', len(contents))
  254. return Response(contents, status=status, headers=headers, content_type='application/json')
  255. '''
  256. '''
  257. def make_info_log(self, log):
  258. LOGGER.info('\033[1;34m[INFO] --> \033[m{}'.format(log))
  259. '''
  260. New purchase resource route
  261. '''
  262. @http.route('/eiru_purchases/init', auth='user', methods=['GET'], cors='*')
  263. def init_purchase(self, **kw):
  264. self.make_info_log('Preparing data to {}'.format(kw.get('mode')))
  265. return self.make_gzip_response({
  266. 'date': self.get_server_date(),
  267. 'user': self.get_user(),
  268. 'currencies': self.get_currencies_from_journal(),
  269. 'journals': self.get_journals(),
  270. 'suppliers': self.get_suppliers(),
  271. 'products': self.get_products(kw.get('mode')),
  272. 'pickingTypes': self.get_picking_types(),
  273. 'paymentTerms': self.get_payment_terms(),
  274. 'banks': self.get_banks(),
  275. 'bankPaymentTypes': self.get_bank_payment_types(),
  276. 'chequeTypes': self.get_cheque_types()
  277. })
  278. '''
  279. Create supplier and return data
  280. '''
  281. @http.route('/eiru_purchases/create_supplier', type='json', auth='user', methods=['POST'], cors='*')
  282. def create_supplier(self, **kw):
  283. self.make_info_log('Creating supplier')
  284. supplier = request.env['res.partner'].create({
  285. 'name': kw.get('name'),
  286. 'ruc': kw.get('ruc'),
  287. 'phone': kw.get('phone'),
  288. 'supplier': True,
  289. 'customer': False
  290. })
  291. return {
  292. 'id': supplier.id,
  293. 'name': supplier.name,
  294. 'displayName': supplier.display_name,
  295. 'imageMedium': supplier.image_medium,
  296. 'phone': supplier.phone,
  297. 'mobile': supplier.mobile,
  298. 'email': supplier.email
  299. }
  300. '''
  301. Create product and return data
  302. '''
  303. @http.route('/eiru_purchases/create_product', type='json', auth='user', methods=['POST'], cors='*')
  304. def create_product(self, **kw):
  305. self.make_info_log('Creating product')
  306. product = request.env['product.template'].create({
  307. 'name': kw.get('name'),
  308. 'standard_price': float(kw.get('price')),
  309. 'ean13': kw.get('ean13')
  310. })
  311. return {
  312. 'id': product.id,
  313. 'name': product.name,
  314. 'displayName': product.display_name,
  315. 'ean13': product.ean13,
  316. 'imageMedium': product.image_medium,
  317. 'standardPrice': product.standard_price,
  318. 'variantCount': product.product_variant_count,
  319. 'price': product.list_price,
  320. 'minimumPrice': product.minimum_price,
  321. 'maximumPrice': product.maximum_price,
  322. 'variants': [{
  323. 'id': variant.id,
  324. 'name': variant.name,
  325. 'displayName': variant.display_name,
  326. 'ean13': variant.ean13,
  327. 'imageMedium': variant.image_medium,
  328. 'standardPrice': product.standard_price,
  329. 'price': variant.standard_price,
  330. 'minimumPrice': product.minimum_price,
  331. 'maximumPrice': product.maximum_price
  332. } for variant in product.product_variant_ids if variant.active]
  333. }
  334. '''
  335. Get currency id based on journal
  336. '''
  337. def get_currency_id(self, journal_id):
  338. journal = request.env['account.journal'].browse(journal_id)
  339. return journal.default_debit_account_id.currency_id.id or journal.default_debit_account_id.company_currency_id.id
  340. '''
  341. Check currency in pricelist and return it
  342. '''
  343. def get_pricelist_id(self, currency_id):
  344. pricelist = request.env['product.pricelist'].search([('active', '=', True), ('type', '=', 'sale')])
  345. if not True in pricelist.mapped(lambda p: p.currency_id.id == currency_id):
  346. pricelist = pricelist[0].copy()
  347. pricelist.write({
  348. 'currency_id': currency_id
  349. })
  350. else:
  351. pricelist = pricelist.filtered(lambda p: p.currency_id.id == currency_id)
  352. return pricelist.id
  353. '''
  354. Get default location
  355. '''
  356. def get_stock_location_id(self):
  357. stock_location = request.env['stock.location'].search([('usage', '=', 'internal')])
  358. return stock_location.id
  359. '''
  360. Create purchase order from cart and return id
  361. '''
  362. def create_purchase_order(
  363. self,
  364. supplier_id,
  365. cart_items,
  366. date_order,
  367. currency_id,
  368. pricelist_id,
  369. payment_term_id=None
  370. ):
  371. def get_product_obj(product_id):
  372. return request.env['product.product'].browse(product_id)
  373. lines = []
  374. for item in cart_items:
  375. product = get_product_obj(item.get('id'))
  376. lines += [[0, False, {
  377. 'name': item.get('name'),
  378. 'date_planned': date_order,
  379. 'product_id': product.id,
  380. 'product_qty': float(item.get('quantity')),
  381. 'price_unit': float(item.get('price')),
  382. 'product_uom': product.uom_id.id
  383. }]]
  384. values = {
  385. 'name': '/',
  386. 'partner_id': supplier_id,
  387. 'order_line': lines,
  388. 'date_order': datetime.utcnow().strftime(DATETIME_FORMAT),
  389. 'currency_id': currency_id,
  390. 'pricelist_id': pricelist_id,
  391. 'payment_term_id': payment_term_id,
  392. 'location_id': self.get_stock_location_id(),
  393. 'invoice_method': 'order'
  394. }
  395. return request.env['purchase.order'].create(values)
  396. '''
  397. Confirm purchase order
  398. '''
  399. def confirm_purchase_order(self, purchase_order_id):
  400. purchase_order = request.env['purchase.order'].browse(purchase_order_id)
  401. purchase_order.action_purchase_confirm()
  402. for picking in purchase_order.picking_ids:
  403. picking.force_assign()
  404. picking.action_done()
  405. purchase_order.write({
  406. 'state': 'done'
  407. })
  408. '''
  409. Create invoice
  410. '''
  411. def create_invoice(
  412. self,
  413. supplier_id,
  414. cart_items,
  415. currency_id,
  416. payment_term_id=None,
  417. supplier_invoice_number=None
  418. ):
  419. partner = request.env['res.partner'].browse(supplier_id)
  420. journal = request.env['account.journal'].search([('type', 'in', ['purchase']), ('company_id', '=', partner.company_id.id)])
  421. return request.env['account.invoice'].create({
  422. 'name': '/',
  423. 'partner_id': partner.id,
  424. 'invoice_line': [[0, False, {
  425. 'name': line.get('name'),
  426. 'product_id': int(line.get('id')),
  427. 'quantity': float(line.get('quantity')),
  428. 'price_unit': float(line.get('price'))
  429. }] for line in cart_items],
  430. 'account_id': partner.property_account_payable.id,
  431. 'journal_id': journal.id,
  432. 'currency_id': currency_id,
  433. 'payment_term': payment_term_id,
  434. 'supplier_invoice_number': supplier_invoice_number,
  435. 'type': 'in_invoice'
  436. })
  437. '''
  438. Validate invoice
  439. '''
  440. def prepare_invoice(self, invoice_ids, currency_id, date_today):
  441. assert len(invoice_ids) == 1
  442. invoice = request.env['account.invoice'].browse(invoice_ids)
  443. date_due = parse(date_today) + rd(days=max(invoice.payment_term.line_ids.mapped(lambda x: x.days + x.days2)))
  444. invoice.write({
  445. 'currency_id': currency_id,
  446. 'date_invoice': date_today,
  447. 'date_due': date_due.strftime(DATE_FORMAT),
  448. 'state': 'open'
  449. })
  450. '''
  451. Create move lines
  452. '''
  453. def create_invoice_move_lines(self, invoice_ids, paid_amount, date_today):
  454. assert len(invoice_ids) == 1
  455. invoice = request.env['account.invoice'].browse(invoice_ids)
  456. is_purchase = False
  457. scoped_context = dict(request.context, lang=invoice.partner_id.lang)
  458. invoice_move_lines = invoice._get_analytic_lines()
  459. decimal_precision = request.env['decimal.precision'].precision_get('Account')
  460. compute_taxes = request.env['account.invoice.tax'].compute(invoice.with_context(lang=invoice.partner_id.lang))
  461. invoice.check_tax_lines(compute_taxes)
  462. invoice._recompute_tax_amount()
  463. invoice_move_lines += request.env['account.invoice.tax'].move_line_get(invoice.id)
  464. total, total_currency, invoice_move_lines = invoice.with_context(scoped_context).compute_invoice_totals(invoice.company_id.currency_id, invoice.reference, invoice_move_lines)
  465. if total < 0:
  466. total = total * -1
  467. is_purchase = True
  468. paid_percentage = abs(paid_amount / round(total, decimal_precision))
  469. distributed_percentage = -(paid_percentage / len(invoice.payment_term.line_ids))
  470. payment_lines = []
  471. for line in invoice.payment_term.line_ids:
  472. date_due = (parse(date_today) + rd(days=line.days + line.days2)).strftime(DATE_FORMAT)
  473. if paid_percentage and paid_percentage < 1.0:
  474. payment_lines.append([date_today, paid_percentage])
  475. paid_percentage = paid_amount = 0
  476. if date_due == date_today and line.value_amount:
  477. distributed_percentage = -((payment_lines[0][1] - line.value_amount) / (len(invoice.payment_term.line_ids) - 1))
  478. continue
  479. if line.value != 'balance':
  480. payment_lines.append([date_due, line.value_amount + distributed_percentage])
  481. continue
  482. payment_lines.append([date_due, line.value_amount])
  483. for payment_line in payment_lines:
  484. current_price = round(total * payment_line[1], decimal_precision)
  485. if current_price < 0.0:
  486. continue
  487. paid_amount = paid_amount + current_price
  488. price = current_price if payment_line[1] else round(total - paid_amount, decimal_precision) or total
  489. if is_purchase:
  490. price = price * -1
  491. invoice_move_lines.append({
  492. 'type': 'dest',
  493. 'name': '/',
  494. 'price': price,
  495. 'account_id': invoice.account_id.id,
  496. 'date_maturity': payment_line[0],
  497. '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,
  498. 'currency_id': invoice.currency_id != invoice.company_id.currency_id and invoice.currency_id.id,
  499. 'ref': invoice.type in ('in_invoice', 'in_refund') and invoice.reference or invoice.number
  500. })
  501. payment_lines = []
  502. return invoice_move_lines
  503. '''
  504. Create account move
  505. '''
  506. def create_account_move(self, invoice_ids, invoice_move_lines):
  507. assert len(invoice_ids) == 1
  508. invoice = request.env['account.invoice'].browse(invoice_ids)
  509. accounting_partner = request.env['res.partner']._find_accounting_partner(invoice.partner_id)
  510. move_line_values = [(0, 0, invoice.line_get_convert(line, accounting_partner.id, invoice.date_invoice)) for line in invoice_move_lines]
  511. move_line_values = invoice.group_lines(invoice_move_lines, move_line_values)
  512. move_line_values = invoice.finalize_invoice_move_lines(move_line_values)
  513. ctx = dict(request.context, lang=invoice.partner_id.lang, company_id=invoice.company_id.id)
  514. period = invoice.period_id
  515. if not period:
  516. period = period.with_context(ctx).find(invoice.date_invoice)[:1]
  517. if period:
  518. for line in move_line_values:
  519. line[2]['period_id'] = period.id
  520. ctx['invoice'] = invoice
  521. ctx_nolang = ctx.copy()
  522. ctx_nolang.pop('lang', None)
  523. account_move = request.env['account.move'].with_context(ctx_nolang).create({
  524. 'ref': invoice.reference or invoice.name,
  525. 'line_id': move_line_values,
  526. 'journal_id': invoice.journal_id.with_context(request.context, lang=invoice.partner_id.lang).id,
  527. 'date': invoice.date_invoice,
  528. 'narration': invoice.comment,
  529. 'company_id': invoice.company_id.id,
  530. 'period_id': period.id
  531. })
  532. invoice.with_context(ctx).write({
  533. 'move_id': account_move.id,
  534. 'period_id': account_move.period_id.id,
  535. 'move_name': account_move.name,
  536. })
  537. account_move.post()
  538. return account_move
  539. '''
  540. Number to invoice
  541. '''
  542. def validate_invoice(self, invoice_ids, type=None):
  543. assert len(invoice_ids) == 1
  544. invoice = request.env['account.invoice'].browse(invoice_ids)
  545. invoice.action_number()
  546. invoice.invoice_validate()
  547. if type != 'purchase':
  548. name = 'GASTO' + invoice.name[invoice.name.index('/'):]
  549. invoice.write({
  550. 'number': name,
  551. 'internal_number': name
  552. })
  553. '''
  554. Create voucher
  555. '''
  556. def create_account_voucher(self, account_move_id, journal_id, currency_id, paid_amount):
  557. account_move = request.env['account.move'].browse(account_move_id)
  558. account_journal = request.env['account.journal'].browse(journal_id)
  559. account_voucher = request.env['account.voucher'].create({
  560. 'reference': account_move.name,
  561. 'type': 'payment',
  562. 'journal_id': account_journal.id,
  563. 'company_id': account_move.company_id.id,
  564. 'pre_line': True,
  565. 'amount': paid_amount,
  566. 'period_id': account_move.period_id.id,
  567. 'date': account_move.date,
  568. 'partner_id': account_move.partner_id.id,
  569. 'account_id': account_journal.default_debit_account_id.id,
  570. 'currency_id': currency_id,
  571. 'line_dr_ids': [[0, False, {
  572. 'date_due': l.date_maturity,
  573. 'account_id': l.account_id.id,
  574. 'date_original': l.invoice.date_invoice,
  575. 'move_line_id': l.id,
  576. 'amount_original': abs(l.credit or l.debit or 0.0),
  577. 'amount_unreconciled': abs(l.amount_residual),
  578. 'amount': abs(l.credit) if account_move.date == l.date_maturity else 0.0,
  579. 'reconcile': account_move.date == l.date_maturity,
  580. 'currency_id': currency_id
  581. }] for l in account_move.line_id]
  582. })
  583. account_voucher.action_move_line_create()
  584. return account_voucher
  585. '''
  586. Close a invoice
  587. '''
  588. def close_invoice(self, invoice_ids):
  589. assert len(invoice_ids) == 1
  590. invoice = request.env['account.invoice'].browse(invoice_ids)
  591. if invoice.residual == 0:
  592. invoice.write({
  593. 'state': 'paid'
  594. })
  595. '''
  596. Create account bank statement
  597. '''
  598. def create_bank_statement(self, account_voucher_id, account_bank_statement_lines, date_today):
  599. account_voucher = request.env['account.voucher'].browse(account_voucher_id)
  600. account_bank_statement = request.env['account.bank.statement'].search([('journal_id', '=', account_voucher.journal_id.id), ('date', '=', date_today)])
  601. account_bank_statement_values = {
  602. 'date': date_today,
  603. 'user_id': request.env.user.id,
  604. 'journal_id': account_voucher.journal_id.id,
  605. 'period_id': account_voucher.period_id.id,
  606. 'line_ids': account_bank_statement_lines,
  607. 'state': 'open' if account_voucher.journal_id.type == 'cash' else 'draft'
  608. }
  609. if account_bank_statement:
  610. size = len(account_bank_statement)
  611. if size == 1:
  612. account_bank_statement.write(account_bank_statement_values)
  613. else:
  614. account_bank_statement[size - 1].write(account_bank_statement_values)
  615. else:
  616. account_bank_statement.create(account_bank_statement_values)
  617. return account_bank_statement
  618. '''
  619. Create account bank statement lines
  620. '''
  621. def create_bank_statement_lines(self, account_voucher_id, reference=None):
  622. account_voucher = request.env['account.voucher'].browse(account_voucher_id)
  623. amount = account_voucher.amount
  624. if account_voucher.type == 'payment':
  625. amount = amount * -1
  626. return [[0, False, {
  627. 'name': account_voucher.reference,
  628. 'amount': amount,
  629. 'partner_id': account_voucher.partner_id.id,
  630. 'voucher_id': account_voucher.id,
  631. 'journal_id': account_voucher.journal_id.id,
  632. 'account_id': account_voucher.account_id.id,
  633. 'journal_entry_id': account_voucher.move_id.id,
  634. 'currency_id': account_voucher.currency_id.id,
  635. 'ref': 'POS/' + (reference or '')
  636. }]]
  637. '''
  638. Purchase processing resource route
  639. '''
  640. @http.route('/eiru_purchases/process', type='json', auth='user', methods=['POST'], cors='*')
  641. def process_purchase(self, **kw):
  642. mode = kw.get('mode')
  643. self.make_info_log('Processing {}'.format(mode))
  644. # Get date
  645. date_now = datetime.now(self.get_timezone()).strftime(DATE_FORMAT)
  646. self.make_info_log('Getting date')
  647. # Get currency
  648. currency_id = self.get_currency_id(kw.get('journalId'))
  649. self.make_info_log('Getting currency')
  650. # Get pricelist
  651. pricelist_id = self.get_pricelist_id(currency_id)
  652. self.make_info_log('Product pricelist checked')
  653. invoice = None
  654. if mode == 'purchase':
  655. # Create purchase order
  656. purchase_order = self.create_purchase_order(kw.get('supplierId'), kw.get('items'), date_now, currency_id, pricelist_id, kw.get('paymentTermId'))
  657. self.make_info_log('Purchase order created')
  658. # Confirm purchase
  659. self.confirm_purchase_order(purchase_order.id)
  660. self.make_info_log('Purchase order confirmed')
  661. invoice = purchase_order.invoice_ids
  662. invoice.write({
  663. 'supplier_invoice_number': kw.get('supplierInvoiceNumber', None)
  664. })
  665. else:
  666. invoice = self.create_invoice(kw.get('supplierId'), kw.get('items'), currency_id, kw.get('paymentTermId'), kw.get('supplierInvoiceNumber', None))
  667. self.make_info_log('Invoice created')
  668. invoice_ids = invoice.mapped(lambda x: x.id)
  669. # Validate invoice
  670. self.prepare_invoice(invoice_ids, currency_id, date_now)
  671. self.make_info_log('Invoice prepared')
  672. # Create invoice move lines
  673. invoice_move_lines = self.create_invoice_move_lines(invoice_ids, float(kw.get('payment')), date_now)
  674. self.make_info_log('Invoice move lines created')
  675. # Create account move
  676. account_move = self.create_account_move(invoice_ids, invoice_move_lines)
  677. self.make_info_log('Account move created')
  678. # Validate invoice
  679. self.validate_invoice(invoice_ids, mode)
  680. self.make_info_log('Invoice validated')
  681. # Create account voucher
  682. account_voucher = self.create_account_voucher(account_move.id, kw.get('journalId'), currency_id, float(kw.get('payment')))
  683. self.make_info_log('Account voucher created')
  684. # Close invoice
  685. self.close_invoice(invoice_ids)
  686. self.make_info_log('Attempt close invoice')
  687. # Create account bank statement lines
  688. account_bank_statement_lines = self.create_bank_statement_lines(account_voucher.id)
  689. self.make_info_log('Bank statement lines created')
  690. # Create account bank statement
  691. self.create_bank_statement(account_voucher.id, account_bank_statement_lines, date_now)
  692. self.make_info_log('Bank statement created')
  693. return {
  694. 'status': 'ok'
  695. }