|
@@ -4,6 +4,8 @@ from openerp.http import request
|
|
|
from werkzeug.wrappers import Response
|
|
|
from werkzeug.datastructures import Headers
|
|
|
from datetime import datetime
|
|
|
+from dateutil.relativedelta import relativedelta as rd
|
|
|
+from dateutil.parser import parse
|
|
|
from gzip import GzipFile
|
|
|
from StringIO import StringIO as IO
|
|
|
import simplejson as json
|
|
@@ -11,6 +13,8 @@ import gzip
|
|
|
import logging
|
|
|
|
|
|
LOGGER = logging.getLogger(__name__)
|
|
|
+DATE_FORMAT = '%Y-%m-%d'
|
|
|
+GZIP_COMPRESSION_LEVEL = 9
|
|
|
|
|
|
class Sales(http.Controller):
|
|
|
|
|
@@ -18,7 +22,7 @@ class Sales(http.Controller):
|
|
|
Get server date
|
|
|
'''
|
|
|
def get_server_date(self):
|
|
|
- return datetime.now().strftime('%Y-%m-%d')
|
|
|
+ return datetime.now().strftime(DATE_FORMAT)
|
|
|
|
|
|
'''
|
|
|
Get current user information
|
|
@@ -167,7 +171,7 @@ class Sales(http.Controller):
|
|
|
'''
|
|
|
def make_gzip_response(self, data=None, status=200):
|
|
|
gzip_buffer = IO()
|
|
|
- with GzipFile(mode='wb', compresslevel=9, fileobj=gzip_buffer) as gzip_file:
|
|
|
+ with GzipFile(mode='wb', compresslevel=GZIP_COMPRESSION_LEVEL, fileobj=gzip_buffer) as gzip_file:
|
|
|
gzip_file.write(json.dumps(data))
|
|
|
|
|
|
contents = gzip_buffer.getvalue()
|
|
@@ -264,23 +268,317 @@ class Sales(http.Controller):
|
|
|
} for variant in product.product_variant_ids if variant.active]
|
|
|
}
|
|
|
|
|
|
-
|
|
|
'''
|
|
|
- Create sale
|
|
|
+ Get currency from journal
|
|
|
'''
|
|
|
- @http.route('/eiru_sales/process_sale', type='json', auth='user', methods=['POST'], cors='*')
|
|
|
- def process_sale(self, **kw):
|
|
|
- print(kw)
|
|
|
+ def get_currency(self, journal_id):
|
|
|
+ journal = request.env['account.journal'].browse(journal_id)
|
|
|
+ return journal.default_credit_account_id.currency_id.id or journal.default_credit_account_id.company_currency_id.id
|
|
|
|
|
|
- date_now = datetime.now().strftime('%Y-%m-%d')
|
|
|
+ '''
|
|
|
+ Create sale order from cart items values
|
|
|
+ '''
|
|
|
+ def create_sale_from_cart(self, partner_id, cart_items, date_confirm, currency_id, payment_term_id):
|
|
|
+ return request.env['sale.order'].create({
|
|
|
+ 'partner_id': partner_id,
|
|
|
+ 'order_line': [[0, False, {
|
|
|
+ 'product_id': int(line.get('id')),
|
|
|
+ 'product_uom_qty': float(line.get('quantity')),
|
|
|
+ 'price_unit': float(line.get('price'))
|
|
|
+ }] for line in cart_items],
|
|
|
+ 'picking_policy': 'direct',
|
|
|
+ 'state': 'manual',
|
|
|
+ 'date_confirm': date_confirm,
|
|
|
+ 'currency_id': currency_id,
|
|
|
+ 'payment_term': payment_term_id
|
|
|
+ })
|
|
|
|
|
|
+ '''
|
|
|
+ Confirm sale order
|
|
|
+ '''
|
|
|
+ def confirm_sale_order(self, sale_order_id):
|
|
|
+ return request.env['sale.order'].browse(sale_order_id).action_button_confirm()
|
|
|
|
|
|
- return {
|
|
|
- 'message': 'ok'
|
|
|
+ '''
|
|
|
+ Create invoice from sale order
|
|
|
+ '''
|
|
|
+ def create_invoice(self, sale_order_id, currency_id, date_today):
|
|
|
+ sale_order = request.env['sale.order'].browse(sale_order_id)
|
|
|
+ invoice_id = sale_order.action_invoice_create()
|
|
|
+ invoice = request.env['account.invoice'].browse(invoice_id)
|
|
|
+
|
|
|
+ date_due = parse(date_today) + rd(days=max(invoice.payment_term.line_ids.mapped(lambda x: x.days + x.days2)))
|
|
|
+
|
|
|
+ invoice.write({
|
|
|
+ 'currency_id': currency_id,
|
|
|
+ 'date_invoice': date_today,
|
|
|
+ 'date_due': date_due.strftime(DATE_FORMAT),
|
|
|
+ 'state': 'open'
|
|
|
+ })
|
|
|
+
|
|
|
+ return invoice
|
|
|
+
|
|
|
+ '''
|
|
|
+ Create move lines
|
|
|
+ '''
|
|
|
+ def create_invoice_move_lines(self, invoice_id, paid_amount, date_today):
|
|
|
+ invoice = request.env['account.invoice'].browse(invoice_id)
|
|
|
+ invoice_move_lines = invoice._get_analytic_lines()
|
|
|
+ decimal_precision = request.env['decimal.precision'].precision_get('Account')
|
|
|
+
|
|
|
+ compute_taxes = request.env['account.invoice.tax'].compute(invoice)
|
|
|
+ invoice.check_tax_lines(compute_taxes)
|
|
|
+ invoice._recompute_tax_amount()
|
|
|
+
|
|
|
+ invoice_move_lines += request.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)
|
|
|
+
|
|
|
+ paid_percentage = paid_amount / round(total, decimal_precision)
|
|
|
+ distributed_percentage = -(paid_percentage / len(invoice.payment_term.line_ids))
|
|
|
+
|
|
|
+ payment_lines = []
|
|
|
+
|
|
|
+ for line in invoice.payment_term.line_ids:
|
|
|
+ date_due = (parse(date_today) + rd(days=line.days + line.days2)).strftime(DATE_FORMAT)
|
|
|
+
|
|
|
+ if paid_percentage and paid_percentage < 1.0:
|
|
|
+ payment_lines.append([date_today, paid_percentage])
|
|
|
+ paid_percentage = paid_amount = 0
|
|
|
+
|
|
|
+ if date_due == date_today and line.value_amount:
|
|
|
+ distributed_percentage = -((payment_lines[0][1] - line.value_amount) / (len(invoice.payment_term.line_ids) - 1))
|
|
|
+ continue
|
|
|
+
|
|
|
+ if line.value != 'balance':
|
|
|
+ payment_lines.append([date_due, line.value_amount + distributed_percentage])
|
|
|
+ continue
|
|
|
+
|
|
|
+ payment_lines.append([date_due, line.value_amount])
|
|
|
+
|
|
|
+ for payment_line in payment_lines:
|
|
|
+ current_price = round(total * payment_line[1], decimal_precision)
|
|
|
+
|
|
|
+ if current_price < 0.0:
|
|
|
+ continue
|
|
|
+
|
|
|
+ paid_amount += current_price
|
|
|
+
|
|
|
+ invoice_move_lines.append({
|
|
|
+ 'type': 'dest',
|
|
|
+ 'name': '/',
|
|
|
+ 'price': current_price if payment_line[1] else round(total - paid_amount, decimal_precision) or total,
|
|
|
+ 'account_id': invoice.account_id.id,
|
|
|
+ 'date_maturity': payment_line[0],
|
|
|
+ '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,
|
|
|
+ 'currency_id': invoice.currency_id != invoice.company_id.currency_id and invoice.currency_id.id,
|
|
|
+ 'ref': invoice.reference
|
|
|
+ })
|
|
|
+
|
|
|
+ payment_lines = []
|
|
|
+
|
|
|
+ return invoice_move_lines
|
|
|
+
|
|
|
+ '''
|
|
|
+ Create account move
|
|
|
+ '''
|
|
|
+ def create_account_move(self, invoice_id, invoice_move_lines):
|
|
|
+ invoice = request.env['account.invoice'].browse(invoice_id)
|
|
|
+ accounting_partner = request.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(request.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 = request.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()
|
|
|
+
|
|
|
+ return account_move
|
|
|
+
|
|
|
+ '''
|
|
|
+ Number to invoice
|
|
|
+ '''
|
|
|
+ def number_invoice(self, invoice_id):
|
|
|
+ request.env['account.invoice'].browse(invoice_id).action_number()
|
|
|
+
|
|
|
+ '''
|
|
|
+ Create voucher
|
|
|
+ '''
|
|
|
+ def create_account_voucher(self, account_move_id, journal_id, currency_id, paid_amount):
|
|
|
+ account_move = request.env['account.move'].browse(account_move_id)
|
|
|
+ account_journal = request.env['account.journal'].browse(journal_id)
|
|
|
+
|
|
|
+ account_voucher = request.env['account.voucher'].create({
|
|
|
+ 'reference': account_move.name,
|
|
|
+ 'type': 'receipt',
|
|
|
+ 'journal_id': account_journal.id,
|
|
|
+ 'company_id': account_move.company_id.id,
|
|
|
+ 'pre_line': True,
|
|
|
+ 'amount': paid_amount,
|
|
|
+ 'period_id': account_move.period_id.id,
|
|
|
+ 'date': account_move.date,
|
|
|
+ 'partner_id': account_move.partner_id.id,
|
|
|
+ 'account_id': account_journal.default_credit_account_id.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()
|
|
|
+
|
|
|
+ return account_voucher
|
|
|
+
|
|
|
+ '''
|
|
|
+ Close a invoice
|
|
|
+ '''
|
|
|
+ def close_invoice(self, invoice_id):
|
|
|
+ invoice = request.env['account.invoice'].browse(invoice_id)
|
|
|
+
|
|
|
+ if invoice.residual == 0:
|
|
|
+ invoice.write({
|
|
|
+ 'state': 'paid'
|
|
|
+ })
|
|
|
+
|
|
|
+ '''
|
|
|
+ Create account bank statement lines
|
|
|
+ '''
|
|
|
+ def create_bank_statement_lines(self, account_voucher_id, reference=None):
|
|
|
+ account_voucher = request.env['account.voucher'].browse(account_voucher_id)
|
|
|
+
|
|
|
+ return [[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/' + reference or ''
|
|
|
+ }]]
|
|
|
+
|
|
|
+
|
|
|
+ '''
|
|
|
+ Create account bank statement
|
|
|
+ '''
|
|
|
+ def create_bank_statement(self, account_voucher_id, account_bank_statement_lines, date_today):
|
|
|
+ account_voucher = request.env['account.voucher'].browse(account_voucher_id)
|
|
|
+ account_bank_statement = self.env['account.bank.statement'].search([('journal_id', '=', account_voucher.journal_id.id), ('date', '=', date_today)])
|
|
|
+
|
|
|
+ account_bank_statement_values = {
|
|
|
+ 'date': date_today,
|
|
|
+ 'user': request.env.user.id,
|
|
|
+ 'journal_id': account_voucher.journal_id.id,
|
|
|
+ 'period_id': account_voucher.period_id.id,
|
|
|
+ 'line_ids': account_bank_statement_lines,
|
|
|
+ 'state': 'open' if account_voucher.journal_id.type == 'cash' else 'draft'
|
|
|
}
|
|
|
|
|
|
+ if account_bank_statement:
|
|
|
+ size = len(account_bank_statement)
|
|
|
+
|
|
|
+ if size == 1:
|
|
|
+ account_bank_statement.write(account_bank_statement_values)
|
|
|
+ else:
|
|
|
+ account_bank_statement[size - 1].write(account_bank_statement_values)
|
|
|
+ else:
|
|
|
+ account_bank_statement.create(account_bank_statement_values)
|
|
|
+
|
|
|
+ return account_bank_statement
|
|
|
+
|
|
|
'''
|
|
|
+ Process sale
|
|
|
'''
|
|
|
- def get_currency(self, journal_id):
|
|
|
- journal = request.env['account.journal'].browse(journal_id)
|
|
|
- return journal.default_credit_account_id.currency_id.id or journal.default_credit_account_id.company_currency_id.id
|
|
|
+ @http.route('/eiru_sales/process_sale', type='json', auth='user', methods=['POST'], cors='*')
|
|
|
+ def process_sale(self, **kw):
|
|
|
+ self.make_info_log('Processing sale...')
|
|
|
+
|
|
|
+ # Get date
|
|
|
+ self.make_info_log('Getting date')
|
|
|
+ date_now = datetime.now().strftime(DATE_FORMAT)
|
|
|
+
|
|
|
+ # Get currency
|
|
|
+ currency_id = self.get_currency(kw.get('journalId'))
|
|
|
+ self.make_info_log('[OK] Getting journal')
|
|
|
+
|
|
|
+ # Create sale orde
|
|
|
+ sale_order = self.create_sale_from_cart(kw.get('customerId'), kw.get('items'), date_now, currency_id, kw.get('paymentTermId'))
|
|
|
+ self.make_info_log('[OK] Creating sale order')
|
|
|
+
|
|
|
+ # Confirm sale
|
|
|
+ self.confirm_sale_order(sale_order.id)
|
|
|
+ self.make_info_log('[OK] Confirm sale order')
|
|
|
+
|
|
|
+ # Create invoice
|
|
|
+ invoice = self.create_invoice(sale_order.id, currency_id, date_now)
|
|
|
+ self.make_info_log('[OK] Creating invoice')
|
|
|
+
|
|
|
+ # Create invoice move lines
|
|
|
+ invoice_move_lines = self.create_invoice_move_lines(invoice.id, kw.get('total', 0), date_now)
|
|
|
+ self.make_info_log('[OK] Creating invoice move lines')
|
|
|
+
|
|
|
+ # Create account move
|
|
|
+ account_move = self.Creatingnt_move(invoice.id, invoice_move_lines)
|
|
|
+ self.make_info_log('[OK] Creating account move')
|
|
|
+
|
|
|
+ # Number invoice
|
|
|
+ self.number_invoice(invoice.id)
|
|
|
+ self.make_info_log('[OK] Number invoice')
|
|
|
+
|
|
|
+ # Create account voucher
|
|
|
+ account_voucher = self.create_account_voucher(account_move.id, kw.get('journalId'), currency_id, float(kw.get('payment')))
|
|
|
+ self.make_info_log('[OK] Creating account voucher')
|
|
|
+
|
|
|
+ # Close invoice
|
|
|
+ self.close_invoice(invoice.id)
|
|
|
+ self.make_info_log('[OK] Closing invoice')
|
|
|
+
|
|
|
+ # Create account bank statement lines
|
|
|
+ account_bank_statement_lines = self.create_bank_statement_lines(account_voucher.id)
|
|
|
+ self.make_info_log('[OK] Creating account bank statement lines')
|
|
|
+
|
|
|
+ # Create bank statement
|
|
|
+ self.create_bank_statement(account_voucher.id, account_bank_statement_lines, date_today)
|
|
|
+ self.make_info_log('[OK] Creating account bank statement')
|
|
|
+
|
|
|
+ return {
|
|
|
+ 'process': True
|
|
|
+ }
|