1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
|
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import odoo
import time
from odoo import fields
from odoo.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.warehouse = self.env['stock.warehouse'].search([('company_id', '=', self.env.company.id)], limit=1)
self.partner = self.env['res.partner'].create({'name': 'Partner 1'})
self.category = self.env.ref('product.product_category_all')
self.category = self.category.copy({'name': 'New category','property_valuation': 'real_time'})
account_type_rcv = self.env.ref('account.data_account_type_receivable')
account_type_inc = self.env.ref('account.data_account_type_revenue')
account_type_exp = self.env.ref('account.data_account_type_expenses')
self.account = self.env['account.account'].create({'name': 'Receivable', 'code': 'RCV00' , 'user_type_id': account_type_rcv.id, 'reconcile': True})
account_expense = self.env['account.account'].create({'name': 'Expense', 'code': 'EXP00' , 'user_type_id': account_type_exp.id, 'reconcile': True})
account_income = self.env['account.account'].create({'name': 'Income', 'code': 'INC00' , 'user_type_id': account_type_inc.id, 'reconcile': True})
account_output = self.env['account.account'].create({'name': 'Output', 'code': 'OUT00' , 'user_type_id': account_type_exp.id, 'reconcile': True})
account_valuation = self.env['account.account'].create({'name': 'Valuation', 'code': 'STV00', 'user_type_id': account_type_exp.id, 'reconcile': True})
self.partner.property_account_receivable_id = self.account
self.category.property_account_income_categ_id = account_income
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 = account_valuation
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.env['product.product'].create({
'name': 'New product',
'standard_price': 100,
'available_in_pos': True,
'type': 'product',
})
self.company.anglo_saxon_accounting = True
self.company.point_of_sale_update_stock_quantities = 'real'
self.product.categ_id = self.category
self.product.property_account_expense_id = account_expense
self.product.property_account_income_id = account_income
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'})
self.sale_journal = self.env['account.journal'].create({'name': 'SALE journal', 'type': 'sale', 'code': 'INV00'})
self.pos_config.invoice_journal_id = self.sale_journal
self.cash_payment_method = self.env['pos.payment.method'].create({
'name': 'Cash Test',
'is_cash_count': True,
'cash_journal_id': self.cash_journal.id,
'receivable_account_id': self.account.id,
})
self.pos_config.write({'payment_method_ids': [(6, 0, self.cash_payment_method.ids)]})
@odoo.tests.tagged('post_install', '-at_install')
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(check_coa=False)
current_session = self.pos_config.current_session_id
self.cash_journal.loss_account_id = self.account
# 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,
'price_subtotal': 450,
'price_subtotal_incl': 450,
})],
'amount_total': 450,
'amount_tax': 0,
'amount_paid': 0,
'amount_return': 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,
'payment_method_id': self.cash_payment_method.id,
})
# 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.')
self.assertEqual(self.pos_order_pos0.amount_paid, 450, 'Amount paid for the order should be updated.')
# I close the current session to generate the journal entries
current_session_id = self.pos_config.current_session_id
current_session_id._check_pos_session_balance()
current_session_id.action_pos_session_close()
self.assertEqual(current_session_id.state, 'closed', 'Check that session is closed')
# Check if there is account_move in the order.
# There shouldn't be because the order is not invoiced.
self.assertFalse(self.pos_order_pos0.account_move, 'There should be no invoice in the order.')
# 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 = current_session.move_id.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")
def _prepare_pos_order(self):
""" Set the cost method of `self.product` as FIFO. Receive 5@5 and 5@1 and
create a `pos.order` record selling 7 units @ 450.
"""
# check fifo Costing Method of product.category
self.product.categ_id.property_cost_method = 'fifo'
self.product.standard_price = 5.0
self.env['stock.quant'].with_context(inventory_mode=True).create({
'product_id': self.product.id,
'inventory_quantity': 5.0,
'location_id': self.warehouse.lot_stock_id.id,
})
self.product.standard_price = 1.0
self.env['stock.quant'].with_context(inventory_mode=True).create({
'product_id': self.product.id,
'inventory_quantity': 10.0,
'location_id': self.warehouse.lot_stock_id.id,
})
self.assertEqual(self.product.value_svl, 30, "Value should be (5*5 + 5*1) = 30")
self.assertEqual(self.product.quantity_svl, 10)
self.pos_config.module_account = True
self.pos_config.open_session_cb(check_coa=False)
pos_order_values = {
'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': 7.0,
'price_subtotal': 7 * 450,
'price_subtotal_incl': 7 * 450,
})],
'amount_total': 7 * 450,
'amount_tax': 0,
'amount_paid': 0,
'amount_return': 0,
}
return self.PosOrder.create(pos_order_values)
def test_fifo_valuation_no_invoice(self):
"""Register a payment and validate a session after selling a fifo
product without making an invoice for the customer"""
pos_order_pos0 = self._prepare_pos_order()
context_make_payment = {"active_ids": [pos_order_pos0.id], "active_id": pos_order_pos0.id}
self.pos_make_payment_0 = self.PosMakePayment.with_context(context_make_payment).create({
'amount': 7 * 450.0,
'payment_method_id': self.cash_payment_method.id,
})
# register the payment
context_payment = {'active_id': pos_order_pos0.id}
self.pos_make_payment_0.with_context(context_payment).check()
# validate the session
current_session_id = self.pos_config.current_session_id
current_session_id.action_pos_session_validate()
# check the anglo saxon move lines
# with uninvoiced orders, the account_move field of pos.order is empty.
# the accounting lines are in move_id of pos.session.
session_move = pos_order_pos0.session_id.move_id
line = session_move.line_ids.filtered(lambda l: l.debit and l.account_id == self.category.property_account_expense_categ_id)
self.assertEqual(session_move.journal_id, self.pos_config.journal_id)
self.assertEqual(line.debit, 27, 'As it is a fifo product, the move\'s value should be 5*5 + 2*1')
def test_fifo_valuation_with_invoice(self):
"""Register a payment and validate a session after selling a fifo
product and make an invoice for the customer"""
pos_order_pos0 = self._prepare_pos_order()
context_make_payment = {"active_ids": [pos_order_pos0.id], "active_id": pos_order_pos0.id}
self.pos_make_payment_0 = self.PosMakePayment.with_context(context_make_payment).create({
'amount': 7 * 450.0,
'payment_method_id': self.cash_payment_method.id,
})
# register the payment
context_payment = {'active_id': pos_order_pos0.id}
self.pos_make_payment_0.with_context(context_payment).check()
# Create the customer invoice
pos_order_pos0.action_pos_order_invoice()
# validate the session
current_session_id = self.pos_config.current_session_id
current_session_id.action_pos_session_validate()
# check the anglo saxon move lines
line = pos_order_pos0.account_move.line_ids.filtered(lambda l: l.debit and l.account_id == self.category.property_account_expense_categ_id)
self.assertEqual(pos_order_pos0.account_move.journal_id, self.pos_config.invoice_journal_id)
self.assertEqual(line.debit, 27, 'As it is a fifo product, the move\'s value should be 5*5 + 2*1')
|