# -*- coding: utf-8 -*- from openerp import api, fields, models from openerp.exceptions import except_orm from datetime import datetime from dateutil.relativedelta import relativedelta as rd from dateutil.parser import parse class AccountVoucher(models.Model): _inherit = 'account.voucher' @api.model def create_from_pos(self, values): date_now = fields.Date.context_today(self) date_format = '%Y-%m-%d' # Step 1: Select currency based on selected journal journal = self.env['account.journal'].browse(int(values['journal_id'])) currency_id = journal.default_credit_account_id.currency_id.id or journal.default_credit_account_id.company_currency_id.id # Step 2: Check product pricelist pricelist_model = self.env['product.pricelist'] pricelist = pricelist_model.search([('active', '=', True), ('type', '=', 'sale')]) if not len([p.id for p in pricelist if p.currency_id.id == currency_id]): pricelist = pricelist[0].copy() pricelist.write({ 'currency_id': currency_id }) else: pricelist = pricelist[0] # Step 3: Create sale order and confirm sale_order = self.env['sale.order'].create({ 'partner_id': values.get('customer_id'), 'order_line': [[0, False, { 'product_id': int(v.get('id')), 'product_uom_qty': float(v.get('qty')), 'price_unit': float(v.get('price')), 'discount': (1.0 - float(v.get('discount'))) * 100, }] for v in values.get('cart_items', [])], 'picking_policy': 'direct', 'state': 'manual', 'date_confirm': date_now, 'currency_id': currency_id, 'pricelist_id': pricelist.id, 'payment_term': values.get('payment_term_id') }) sale_order.action_button_confirm() # Step 4: Create invoice and calculate due date invoice = self.env['account.invoice'].browse(sale_order.action_invoice_create()) due_date = parse(date_now) + rd(days=max(invoice.payment_term.line_ids.mapped(lambda x: x.days + x.days2))) invoice.write({ 'currency_id': currency_id, 'date_invoice': date_now, 'date_due': due_date.strftime(date_format), 'state': 'open' }) # Step 5: Create invoice move lines amount_paid = float(values['amount_paid']) decimal_precision = self.env['decimal.precision'].precision_get('Account') invoice_move_lines = invoice._get_analytic_lines() compute_taxes = self.env['account.invoice.tax'].compute(invoice) invoice.check_tax_lines(compute_taxes) invoice._recompute_tax_amount() invoice_move_lines += self.env['account.invoice.tax'].move_line_get(invoice.id) total, total_currency, invoice_move_lines = invoice.compute_invoice_totals(invoice.company_id.currency_id, invoice.reference, invoice_move_lines) percent_paid = amount_paid / round(total, decimal_precision) distribute_percent = -(percent_paid / len(invoice.payment_term.line_ids)) total_lines = [] for line in invoice.payment_term.line_ids: due_date = (parse(date_now) + rd(days=line.days + line.days2)).strftime(date_format) if percent_paid and percent_paid < 1: total_lines.append([date_now, percent_paid]) percent_paid = amount_paid = 0 if due_date == date_now and line.value_amount: distribute_percent = -((total_lines[0][1] - line.value_amount) / (len(invoice.payment_term.line_ids) - 1)) continue if line.value != 'balance': total_lines.append([due_date, line.value_amount + distribute_percent]) continue total_lines.append([due_date, line.value_amount]) for total_line in total_lines: current_price = round(total * total_line[1], decimal_precision) if current_price < 0.0: continue amount_paid += current_price invoice_move_lines.append({ 'type': 'dest', 'name': '/', 'price': current_price if total_line[1] else round(total - amount_paid, decimal_precision) or total, 'account_id': invoice.account_id.id, 'date_maturity': total_line[0], 'amount_currency': invoice.company_id.currency_id.compute(total_line[1], invoice.currency_id) if invoice.currency_id != invoice.company_id.currency_id else False, 'currency_id': invoice.currency_id != invoice.company_id.currency_id and invoice.currency_id.id, 'ref': invoice.reference }) total_lines = [] # Step 6: Create account move accounting_partner = self.env['res.partner']._find_accounting_partner(invoice.partner_id) move_line_values = [(0, 0, invoice.line_get_convert(line, accounting_partner.id, invoice.date_invoice)) for line in invoice_move_lines] move_line_values = invoice.group_lines(invoice_move_lines, move_line_values) move_line_values = invoice.finalize_invoice_move_lines(move_line_values) ctx = dict(self._context, lang=invoice.partner_id.lang, company_id=invoice.company_id.id) period = invoice.period_id if not period: period = period.with_context(ctx).find(invoice.date_invoice)[:1] if period: for line in move_line_values: line[2]['period_id'] = period.id ctx['invoice'] = invoice ctx_nolang = ctx.copy() ctx_nolang.pop('lang', None) account_move = self.env['account.move'].with_context(ctx_nolang).create({ 'ref': invoice.reference or invoice.name, 'line_id': move_line_values, 'journal_id': invoice.journal_id.id, 'date': invoice.date_invoice, 'narration': invoice.comment, 'company_id': invoice.company_id.id, 'period_id': period.id }) invoice.with_context(ctx).write({ 'move_id': account_move.id, 'period_id': account_move.period_id.id, 'move_name': account_move.name, }) account_move.post() # Step 7: Write a number for invoice invoice.action_number() # Step 8: Create voucher account_voucher = self.create({ 'reference': account_move.name, 'type': 'receipt', 'journal_id': int(values['journal_id']), 'company_id': account_move.company_id.id, 'pre_line': True, 'amount': float(values['amount_paid']), 'period_id': account_move.period_id.id, 'date': account_move.date, 'partner_id': account_move.partner_id.id, 'account_id': int(values['account_id']), 'currency_id': currency_id, 'line_cr_ids': [[0, False, { 'date_due': l.date_maturity, 'account_id': l.account_id.id, 'date_original': l.invoice.date_invoice, 'move_line_id': l.id, 'amount_original': abs(l.credit or l.debit or 0.0), 'amount_unreconciled': abs(l.amount_residual), 'amount': abs(l.debit) if account_move.date == l.date_maturity else 0.0, 'reconcile': account_move.date == l.date_maturity, 'currency_id': currency_id }] for l in account_move.line_id] }) account_voucher.action_move_line_create() # Step 9: Close a invoice if invoice.residual == 0: invoice.write({ 'state': 'paid' }) # Step 10: Save bank statement bank_statement_lines = [[0, False, { 'name': account_voucher.reference, 'amount': account_voucher.amount, 'partner_id': account_voucher.partner_id.id, 'voucher_id': account_voucher.id, 'journal_id': account_voucher.journal_id.id, 'account_id': account_voucher.account_id.id, 'journal_entry_id': account_voucher.move_id.id, 'currency_id': account_voucher.currency_id.id, 'ref': 'POS/' + values.get('payment_reference') or '' }]] account_bank_statement = self.env['account.bank.statement'].search([('journal_id', '=', account_voucher.journal_id.id), ('date', '=', date_now)]) account_bank_statement_values = { 'date': date_now, 'user_id': self.env.user.id, 'journal_id': account_voucher.journal_id.id, 'period_id': account_voucher.period_id.id, 'line_ids': bank_statement_lines, 'state': 'open' if account_voucher.journal_id.type == 'cash' else 'draft' } if account_bank_statement: if len(account_bank_statement) == 1: account_bank_statement.write(account_bank_statement_values) else: account_bank_statement[len(account_bank_statement) - 1].write(account_bank_statement_values) else: account_bank_statement.create(account_bank_statement_values) # Step 11: Return values return { 'action_id': self.env['ir.actions.report.xml'].search([('report_name', '=', 'account.report_invoice')]).id, 'invoice_id': invoice.id }