[FIX] point_of_sale, stock_account: POS Anglo-Saxon Accounting
Anglo-Saxon Accounting entries are not created when the POS session was closed with button "Close and post entries opw:802727
This commit is contained in:
@@ -859,24 +859,7 @@ class AccountInvoice(models.Model):
|
||||
|
||||
@api.model
|
||||
def line_get_convert(self, line, part):
|
||||
return {
|
||||
'date_maturity': line.get('date_maturity', False),
|
||||
'partner_id': part,
|
||||
'name': line['name'],
|
||||
'debit': line['price'] > 0 and line['price'],
|
||||
'credit': line['price'] < 0 and -line['price'],
|
||||
'account_id': line['account_id'],
|
||||
'analytic_line_ids': line.get('analytic_line_ids', []),
|
||||
'amount_currency': line['price'] > 0 and abs(line.get('amount_currency', False)) or -abs(line.get('amount_currency', False)),
|
||||
'currency_id': line.get('currency_id', False),
|
||||
'quantity': line.get('quantity', 1.00),
|
||||
'product_id': line.get('product_id', False),
|
||||
'product_uom_id': line.get('uom_id', False),
|
||||
'analytic_account_id': line.get('account_analytic_id', False),
|
||||
'invoice_id': line.get('invoice_id', False),
|
||||
'tax_ids': line.get('tax_ids', False),
|
||||
'tax_line_id': line.get('tax_line_id', False),
|
||||
}
|
||||
return self.env['product.product']._convert_prepared_anglosaxon_line(line, part)
|
||||
|
||||
@api.multi
|
||||
def action_cancel(self):
|
||||
@@ -1455,3 +1438,27 @@ class MailComposeMessage(models.Model):
|
||||
invoice.sent = True
|
||||
invoice.message_post(body=_("Invoice sent"))
|
||||
return super(MailComposeMessage, self).send_mail(auto_commit=auto_commit)
|
||||
|
||||
class ProductProduct(models.Model):
|
||||
_inherit = "product.product"
|
||||
|
||||
@api.model
|
||||
def _convert_prepared_anglosaxon_line(self, line, partner):
|
||||
return {
|
||||
'date_maturity': line.get('date_maturity', False),
|
||||
'partner_id': partner,
|
||||
'name': line['name'],
|
||||
'debit': line['price'] > 0 and line['price'],
|
||||
'credit': line['price'] < 0 and -line['price'],
|
||||
'account_id': line['account_id'],
|
||||
'analytic_line_ids': line.get('analytic_line_ids', []),
|
||||
'amount_currency': line['price'] > 0 and abs(line.get('amount_currency', False)) or -abs(line.get('amount_currency', False)),
|
||||
'currency_id': line.get('currency_id', False),
|
||||
'quantity': line.get('quantity', 1.00),
|
||||
'product_id': line.get('product_id', False),
|
||||
'product_uom_id': line.get('uom_id', False),
|
||||
'analytic_account_id': line.get('account_analytic_id', False),
|
||||
'invoice_id': line.get('invoice_id', False),
|
||||
'tax_ids': line.get('tax_ids', False),
|
||||
'tax_line_id': line.get('tax_line_id', False),
|
||||
}
|
||||
|
||||
@@ -9,3 +9,4 @@ import res_users
|
||||
import res_partner
|
||||
import wizard
|
||||
import res_config
|
||||
import tests
|
||||
|
||||
@@ -1319,7 +1319,40 @@ class pos_order(osv.osv):
|
||||
grouped_data = {}
|
||||
have_to_group_by = session and session.config_id.group_by or False
|
||||
rounding_method = session and session.config_id.company_id.tax_calculation_rounding_method
|
||||
def add_anglosaxon_lines(grouped_data):
|
||||
Product = self.pool['product.product']
|
||||
Analytic = self.pool['account.analytic.account']
|
||||
for product_key in list(grouped_data.keys()):
|
||||
if product_key[0] == "product":
|
||||
line = grouped_data[product_key][0]
|
||||
product = Product.browse(cr, uid, line['product_id'], context=context)
|
||||
# In the SO part, the entries will be inverted by function compute_invoice_totals
|
||||
price_unit = - product._get_anglo_saxon_price_unit()
|
||||
account_analytic = Analytic.browse(cr, uid, line.get('analytic_account_id'), context=context)
|
||||
res = Product._anglo_saxon_sale_move_lines(cr, uid,
|
||||
line['name'], product, product.uom_id, line['quantity'], price_unit,
|
||||
fiscal_position=order.fiscal_position_id,
|
||||
account_analytic=account_analytic, context=context)
|
||||
if res:
|
||||
line1, line2 = res
|
||||
line1 = Product._convert_prepared_anglosaxon_line(cr, uid, line1, order.partner_id, context=context)
|
||||
insert_data('counter_part', {
|
||||
'name': line1['name'],
|
||||
'account_id': line1['account_id'],
|
||||
'credit': line1['credit'] or 0.0,
|
||||
'debit': line1['debit'] or 0.0,
|
||||
'partner_id': line1['partner_id']
|
||||
|
||||
})
|
||||
|
||||
line2 = Product._convert_prepared_anglosaxon_line(cr, uid, line2, order.partner_id, context=context)
|
||||
insert_data('counter_part', {
|
||||
'name': line2['name'],
|
||||
'account_id': line2['account_id'],
|
||||
'credit': line2['credit'] or 0.0,
|
||||
'debit': line2['debit'] or 0.0,
|
||||
'partner_id': line2['partner_id']
|
||||
})
|
||||
for order in self.browse(cr, uid, ids, context=context):
|
||||
if order.account_move:
|
||||
continue
|
||||
@@ -1463,6 +1496,9 @@ class pos_order(osv.osv):
|
||||
|
||||
order.write({'state':'done', 'account_move': move_id})
|
||||
|
||||
if ids and order.company_id.anglo_saxon_accounting:
|
||||
add_anglosaxon_lines(grouped_data)
|
||||
|
||||
all_lines = []
|
||||
for group_key, group_data in grouped_data.iteritems():
|
||||
for value in group_data:
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
#Accounting tests written in python should extend the class AccountingTestCase.
|
||||
#See its doc for more info.
|
||||
|
||||
from . import test_anglo_saxon
|
||||
@@ -0,0 +1,99 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import openerp
|
||||
import time
|
||||
from openerp import fields
|
||||
|
||||
from openerp.tests import common
|
||||
|
||||
|
||||
class TestAngloSaxonCommon(common.TransactionCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestAngloSaxonCommon, self).setUp()
|
||||
self.PosMakePayment = self.env['pos.make.payment']
|
||||
self.PosOrder = self.env['pos.order']
|
||||
self.Statement = self.env['account.bank.statement']
|
||||
self.company = self.env.ref('base.main_company')
|
||||
self.product = self.env.ref('product.product_product_3')
|
||||
self.partner = self.env.ref('base.res_partner_1')
|
||||
self.category = self.env.ref('product.product_category_1')
|
||||
self.category = self.category.copy({'name': 'New category','property_valuation': 'real_time'})
|
||||
account_type = self.env['account.account.type'].create({'name': 'RCV type', 'type': 'receivable'})
|
||||
self.account = self.env['account.account'].create({'name': 'Receivable', 'code': 'RCV00' , 'user_type_id': account_type.id, 'reconcile': True})
|
||||
account_expense = self.env['account.account'].create({'name': 'Expense', 'code': 'EXP00' , 'user_type_id': account_type.id, 'reconcile': True})
|
||||
account_output = self.env['account.account'].create({'name': 'Output', 'code': 'OUT00' , 'user_type_id': account_type.id, 'reconcile': True})
|
||||
self.partner.property_account_receivable_id = self.account
|
||||
self.category.property_account_income_categ_id = self.account
|
||||
self.category.property_account_expense_categ_id = account_expense
|
||||
self.category.property_stock_account_input_categ_id = self.account
|
||||
self.category.property_stock_account_output_categ_id = account_output
|
||||
self.category.property_stock_valuation_account_id = self.account
|
||||
self.category.property_stock_journal = self.env['account.journal'].create({'name': 'Stock journal', 'type': 'sale', 'code': 'STK00'})
|
||||
self.pos_config = self.env.ref('point_of_sale.pos_config_main')
|
||||
self.pos_config = self.pos_config.copy({'name': 'New POS config'})
|
||||
self.product = self.product.copy({'name': 'New product','standard_price': 100})
|
||||
self.company.anglo_saxon_accounting = True
|
||||
self.product.categ_id = self.category
|
||||
sale_journal = self.env['account.journal'].create({'name': 'POS journal', 'type': 'sale', 'code': 'POS00'})
|
||||
self.pos_config.journal_id = sale_journal
|
||||
self.cash_journal = self.env['account.journal'].create({'name': 'CASH journal', 'type': 'cash', 'code': 'CSH00'})
|
||||
|
||||
|
||||
class TestAngloSaxonFlow(TestAngloSaxonCommon):
|
||||
|
||||
def test_create_account_move_line(self):
|
||||
# This test will check that the correct journal entries are created when a product in real time valuation
|
||||
# is sold in a company using anglo-saxon
|
||||
self.pos_config.open_session_cb()
|
||||
self.pos_config.current_session_id.write({'journal_ids': [(6, 0, [self.cash_journal.id])]})
|
||||
self.cash_journal.loss_account_id = self.account
|
||||
self.pos_statement = self.Statement.create({
|
||||
'balance_start': 0.0,
|
||||
'balance_end_real': 0.0,
|
||||
'date': time.strftime('%Y-%m-%d'),
|
||||
'journal_id': self.cash_journal.id,
|
||||
'company_id': self.company.id,
|
||||
'name': 'pos session test',
|
||||
})
|
||||
self.pos_config.current_session_id.write({'statement_ids': [(6, 0, [self.pos_statement.id])]})
|
||||
|
||||
# I create a PoS order with 1 unit of New product at 450 EUR
|
||||
self.pos_order_pos0 = self.PosOrder.create({
|
||||
'company_id': self.company.id,
|
||||
'partner_id': self.partner.id,
|
||||
'pricelist_id': self.company.partner_id.property_product_pricelist.id,
|
||||
'session_id': self.pos_config.current_session_id.id,
|
||||
'lines': [(0, 0, {
|
||||
'name': "OL/0001",
|
||||
'product_id': self.product.id,
|
||||
'price_unit': 450,
|
||||
'discount': 0.0,
|
||||
'qty': 1.0
|
||||
})]
|
||||
})
|
||||
|
||||
# I make a payment to fully pay the order
|
||||
context_make_payment = {"active_ids": [self.pos_order_pos0.id], "active_id": self.pos_order_pos0.id}
|
||||
self.pos_make_payment_0 = self.PosMakePayment.with_context(context_make_payment).create({
|
||||
'amount': 450.0
|
||||
})
|
||||
|
||||
# I click on the validate button to register the payment.
|
||||
context_payment = {'active_id': self.pos_order_pos0.id}
|
||||
self.pos_make_payment_0.with_context(context_payment).check()
|
||||
|
||||
# I check that the order is marked as paid
|
||||
self.assertEqual(self.pos_order_pos0.state, 'paid', 'Order should be in paid state.')
|
||||
|
||||
# I close the current session to generate the journal entries
|
||||
self.pos_config.current_session_id.wkf_action_close()
|
||||
|
||||
# I test that the generated journal entries are correct.
|
||||
account_output = self.category.property_stock_account_output_categ_id
|
||||
expense_account = self.category.property_account_expense_categ_id
|
||||
aml = self.pos_order_pos0.account_move.line_ids
|
||||
aml_output = aml.filtered(lambda l: l.account_id.id == account_output.id)
|
||||
aml_expense = aml.filtered(lambda l: l.account_id.id == expense_account.id)
|
||||
self.assertEqual(aml_output.credit, self.product.standard_price, "Cost of Good Sold entry missing or mismatching")
|
||||
self.assertEqual(aml_expense.debit, self.product.standard_price, "Cost of Good Sold entry missing or mismatching")
|
||||
@@ -24,17 +24,78 @@ class stock_inventory(osv.osv):
|
||||
ctx['force_period_date'] = inv.accounting_date
|
||||
return super(stock_inventory, self).post_inventory(cr, uid, inv, context=ctx)
|
||||
|
||||
class ProductProduct(models.Model):
|
||||
_inherit = "product.product"
|
||||
|
||||
@api.model
|
||||
def _anglo_saxon_sale_move_lines(self, name, product, uom, qty, price_unit, currency=False, amount_currency=False, fiscal_position=False, account_analytic=False):
|
||||
"""Prepare dicts describing new journal COGS journal items for a product sale.
|
||||
|
||||
Returns a dict that should be passed to `_convert_prepared_anglosaxon_line()` to
|
||||
obtain the creation value for the new journal items.
|
||||
|
||||
:param Model product: a product.product record of the product being sold
|
||||
:param Model uom: a product.uom record of the UoM of the sale line
|
||||
:param Integer qty: quantity of the product being sold
|
||||
:param Integer price_unit: unit price of the product being sold
|
||||
:param Model currency: a res.currency record from the order of the product being sold
|
||||
:param Interger amount_currency: unit price in the currency from the order of the product being sold
|
||||
:param Model fiscal_position: a account.fiscal.position record from the order of the product being sold
|
||||
:param Model account_analytic: a account.account.analytic record from the line of the product being sold
|
||||
"""
|
||||
|
||||
if product.type == 'product' and product.valuation == 'real_time':
|
||||
accounts = product.product_tmpl_id.get_product_accounts(fiscal_pos=fiscal_position)
|
||||
# debit account dacc will be the output account
|
||||
dacc = accounts['stock_output'].id
|
||||
# credit account cacc will be the expense account
|
||||
cacc = accounts['expense'].id
|
||||
if dacc and cacc:
|
||||
return [
|
||||
{
|
||||
'type': 'src',
|
||||
'name': name[:64],
|
||||
'price_unit': price_unit,
|
||||
'quantity': qty,
|
||||
'price': price_unit * qty,
|
||||
'currency_id': currency and currency.id,
|
||||
'amount_currency': amount_currency,
|
||||
'account_id': dacc,
|
||||
'product_id': product.id,
|
||||
'uom_id': uom.id,
|
||||
'account_analytic_id': account_analytic and account_analytic.id,
|
||||
},
|
||||
|
||||
{
|
||||
'type': 'src',
|
||||
'name': name[:64],
|
||||
'price_unit': price_unit,
|
||||
'quantity': qty,
|
||||
'price': -1 * price_unit * qty,
|
||||
'currency_id': currency and currency.id,
|
||||
'amount_currency': -1 * amount_currency,
|
||||
'account_id': cacc,
|
||||
'product_id': product.id,
|
||||
'uom_id': uom.id,
|
||||
'account_analytic_id': account_analytic and account_analytic.id,
|
||||
},
|
||||
]
|
||||
return []
|
||||
|
||||
@api.model
|
||||
def _get_anglo_saxon_price_unit(self, uom=False):
|
||||
price = self.standard_price
|
||||
if not uom or self.uom_id.id == uom.id:
|
||||
return price
|
||||
return self.uom_id._compute_price(self.uom_id.id, price, to_uom_id=uom.id)
|
||||
|
||||
|
||||
class account_invoice_line(osv.osv):
|
||||
_inherit = "account.invoice.line"
|
||||
|
||||
def _get_anglo_saxon_price_unit(self):
|
||||
self.ensure_one()
|
||||
price = self.product_id.standard_price
|
||||
if not self.uom_id or self.product_id.uom_id == self.uom_id:
|
||||
return price
|
||||
else:
|
||||
return self.product_id.uom_id._compute_price(self.product_id.uom_id.id, price, to_uom_id=self.uom_id.id)
|
||||
return self.product_id._get_anglo_saxon_price_unit(uom=self.uom_id)
|
||||
|
||||
def _get_price(self, cr, uid, inv, company_currency, i_line, price_unit):
|
||||
cur_obj = self.pool.get('res.currency')
|
||||
@@ -72,53 +133,17 @@ class account_invoice(osv.osv):
|
||||
res: The move line entries produced so far by the parent move_line_get.
|
||||
"""
|
||||
inv = i_line.invoice_id
|
||||
company_currency = inv.company_id.currency_id.id
|
||||
company_currency = inv.company_id.currency_id
|
||||
price_unit = i_line._get_anglo_saxon_price_unit()
|
||||
if inv.currency_id != company_currency:
|
||||
currency_id = inv.currency_id.id
|
||||
amount_currency = i_line._get_price(inv, company_currency.id, i_line, price_unit)
|
||||
else:
|
||||
currency_id = False
|
||||
amount_currency = False
|
||||
|
||||
if i_line.product_id.type in ('product', 'consu') and i_line.product_id.valuation == 'real_time':
|
||||
fpos = i_line.invoice_id.fiscal_position_id
|
||||
accounts = i_line.product_id.product_tmpl_id.get_product_accounts(fiscal_pos=fpos)
|
||||
# debit account dacc will be the output account
|
||||
dacc = accounts['stock_output'].id
|
||||
# credit account cacc will be the expense account
|
||||
cacc = accounts['expense'].id
|
||||
if dacc and cacc:
|
||||
price_unit = i_line._get_anglo_saxon_price_unit()
|
||||
if inv.currency_id.id != company_currency:
|
||||
currency_id = inv.currency_id.id
|
||||
amount_currency = self.env['account.invoice.line']._get_price(inv, company_currency, i_line, price_unit)
|
||||
else:
|
||||
currency_id = False
|
||||
amount_currency = False
|
||||
return [
|
||||
{
|
||||
'type':'src',
|
||||
'name': i_line.name[:64],
|
||||
'price_unit': price_unit,
|
||||
'quantity': i_line.quantity,
|
||||
'price': price_unit * i_line.quantity,
|
||||
'currency_id': currency_id,
|
||||
'amount_currency': amount_currency,
|
||||
'account_id':dacc,
|
||||
'product_id':i_line.product_id.id,
|
||||
'uom_id':i_line.uom_id.id,
|
||||
'account_analytic_id': i_line.account_analytic_id.id,
|
||||
},
|
||||
return self.env['product.product']._anglo_saxon_sale_move_lines(i_line.name, i_line.product_id, i_line.uom_id, i_line.quantity, price_unit, currency=currency_id, amount_currency=amount_currency, fiscal_position=inv.fiscal_position_id, account_analytic=i_line.account_analytic_id)
|
||||
|
||||
{
|
||||
'type':'src',
|
||||
'name': i_line.name[:64],
|
||||
'price_unit': price_unit,
|
||||
'quantity': i_line.quantity,
|
||||
'price': -1 * price_unit * i_line.quantity,
|
||||
'currency_id': currency_id,
|
||||
'amount_currency': -1 * amount_currency,
|
||||
'account_id':cacc,
|
||||
'product_id':i_line.product_id.id,
|
||||
'uom_id':i_line.uom_id.id,
|
||||
'account_analytic_id': i_line.account_analytic_id.id,
|
||||
},
|
||||
]
|
||||
return []
|
||||
|
||||
#----------------------------------------------------------
|
||||
# Stock Location
|
||||
|
||||
Reference in New Issue
Block a user