1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # analytic_point_of_sale module for OpenERP, Analytic Point of sale
5 # Copyright (C) 2017 L'Heureux Cyclage (<http://www.heureux-cyclage.org>)
8 # This file is a part of analytic_point_of_sale
10 # analytic_point_of_sale is free software: you can redistribute it and/or
11 # modify it under the terms of the GNU General Public License as published
12 # by the Free Software Foundation, either version 3 of the License, or (at
13 # your option) any later version.
15 # analytic_point_of_sale is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
18 # Public License for more details.
20 # You should have received a copy of the GNU General Public License along
21 # with this program. If not, see <http://www.gnu.org/licenses/>.
23 ##############################################################################
25 from openerp
.osv
import osv
26 from openerp
.osv
import orm
27 from openerp
.osv
import fields
28 from openerp
.tools
.translate
import _
31 class pos_order(orm
.Model
):
32 _inherit
= 'pos.order'
34 def _create_account_move_line(self
, cr
, uid
, ids
, session
=None, move_id
=None, context
=None):
35 # Tricky, via the workflow, we only have one id in the ids variable
36 """Create a account move line of order grouped by products or not."""
37 account_move_obj
= self
.pool
.get('account.move')
38 account_period_obj
= self
.pool
.get('account.period')
39 account_tax_obj
= self
.pool
.get('account.tax')
40 property_obj
= self
.pool
.get('ir.property')
41 cur_obj
= self
.pool
.get('res.currency')
42 shop_obj
= self
.pool
.get('sale.shop')
44 #session_ids = set(order.session_id for order in self.browse(cr, uid, ids, context=context))
46 if session
and not all(session
.id == order
.session_id
.id for order
in self
.browse(cr
, uid
, ids
, context
=context
)):
47 raise osv
.except_osv(_('Error!'), _('Selected orders do not have the same session!'))
50 have_to_group_by
= session
and session
.config_id
.group_by
or False
52 def compute_tax(amount
, tax
, line
):
54 tax_code_id
= tax
['base_code_id']
55 tax_amount
= line
.price_subtotal
* tax
['base_sign']
57 tax_code_id
= tax
['ref_base_code_id']
58 tax_amount
= line
.price_subtotal
* tax
['ref_base_sign']
60 return (tax_code_id
, tax_amount
,)
62 for order
in self
.browse(cr
, uid
, ids
, context
=context
):
63 if order
.account_move
:
65 if order
.state
!= 'paid':
68 current_company
= order
.sale_journal
.company_id
69 analytic_account_id
= order
.shop_id
.project_id
.id
70 print("#DEBUG: analytic_account_id = %s" % analytic_account_id
)
73 account_def
= property_obj
.get(cr
, uid
, 'property_account_receivable', 'res.partner', context
=context
)
75 order_account
= order
.partner_id
and \
76 order
.partner_id
.property_account_receivable
and \
77 order
.partner_id
.property_account_receivable
.id or \
78 account_def
and account_def
.id or current_company
.account_receivable
.id
81 # Create an entry for the sale
82 move_id
= account_move_obj
.create(cr
, uid
, {
84 'journal_id': order
.sale_journal
.id,
87 def insert_data(data_type
, values
):
88 # if have_to_group_by:
90 sale_journal_id
= order
.sale_journal
.id
91 period
= account_period_obj
.find(cr
, uid
, context
=dict(context
or {}, company_id
=current_company
.id, account_period_prefer_normal
=True))[0]
93 # 'quantity': line.qty,
94 # 'product_id': line.product_id.id,
96 'date': order
.date_order
[:10],
98 'journal_id' : sale_journal_id
,
101 'company_id': current_company
.id,
104 if data_type
== 'product':
105 key
= ('product', values
['partner_id'], values
['product_id'], values
['debit'] > 0)
106 elif data_type
== 'tax':
107 key
= ('tax', values
['partner_id'], values
['tax_code_id'], values
['debit'] > 0)
108 elif data_type
== 'counter_part':
109 key
= ('counter_part', values
['partner_id'], values
['account_id'], values
['debit'] > 0)
113 grouped_data
.setdefault(key
, [])
115 # if not have_to_group_by or (not grouped_data[key]):
116 # grouped_data[key].append(values)
121 if not grouped_data
[key
]:
122 grouped_data
[key
].append(values
)
124 current_value
= grouped_data
[key
][0]
125 current_value
['quantity'] = current_value
.get('quantity', 0.0) + values
.get('quantity', 0.0)
126 current_value
['credit'] = current_value
.get('credit', 0.0) + values
.get('credit', 0.0)
127 current_value
['debit'] = current_value
.get('debit', 0.0) + values
.get('debit', 0.0)
128 current_value
['tax_amount'] = current_value
.get('tax_amount', 0.0) + values
.get('tax_amount', 0.0)
130 grouped_data
[key
].append(values
)
132 #because of the weird way the pos order is written, we need to make sure there is at least one line,
133 #because just after the 'for' loop there are references to 'line' and 'income_account' variables (that
134 #are set inside the for loop)
135 #TOFIX: a deep refactoring of this method (and class!) is needed in order to get rid of this stupid hack
136 assert order
.lines
, _('The POS order must have lines when calling this method')
137 # Create an move for each order line
139 cur
= order
.pricelist_id
.currency_id
140 for line
in order
.lines
:
143 for t
in line
.product_id
.taxes_id
:
144 if t
.company_id
.id == current_company
.id:
146 computed_taxes
= account_tax_obj
.compute_all(cr
, uid
, taxes
, line
.price_unit
* (100.0-line
.discount
) / 100.0, line
.qty
)['taxes']
148 for tax
in computed_taxes
:
149 tax_amount
+= cur_obj
.round(cr
, uid
, cur
, tax
['amount'])
150 group_key
= (tax
['tax_code_id'], tax
['base_code_id'], tax
['account_collected_id'], tax
['id'])
152 group_tax
.setdefault(group_key
, 0)
153 group_tax
[group_key
] += cur_obj
.round(cr
, uid
, cur
, tax
['amount'])
155 amount
= line
.price_subtotal
157 # Search for the income account
158 if line
.product_id
.property_account_income
.id:
159 income_account
= line
.product_id
.property_account_income
.id
160 elif line
.product_id
.categ_id
.property_account_income_categ
.id:
161 income_account
= line
.product_id
.categ_id
.property_account_income_categ
.id
163 raise osv
.except_osv(_('Error!'), _('Please define income '\
164 'account for this product: "%s" (id:%d).') \
165 % (line
.product_id
.name
, line
.product_id
.id, ))
167 # Empty the tax list as long as there is no tax code:
170 while computed_taxes
:
171 tax
= computed_taxes
.pop(0)
172 tax_code_id
, tax_amount
= compute_tax(amount
, tax
, line
)
174 # If there is one we stop
178 # Create a move for the line
179 insert_data('product', {
180 'name': line
.product_id
.name
,
181 'quantity': line
.qty
,
182 'product_id': line
.product_id
.id,
183 'account_id': income_account
,
184 'analytic_account_id': analytic_account_id
,
185 'credit': ((amount
>0) and amount
) or 0.0,
186 'debit': ((amount
<0) and -amount
) or 0.0,
187 'tax_code_id': tax_code_id
,
188 'tax_amount': tax_amount
,
189 'partner_id': order
.partner_id
and self
.pool
.get("res.partner")._find
_accounting
_partner
(order
.partner_id
).id or False
192 # For each remaining tax with a code, whe create a move line
193 for tax
in computed_taxes
:
194 tax_code_id
, tax_amount
= compute_tax(amount
, tax
, line
)
200 'product_id':line
.product_id
.id,
201 'quantity': line
.qty
,
202 'account_id': income_account
,
205 'tax_code_id': tax_code_id
,
206 'tax_amount': tax_amount
,
207 'partner_id': order
.partner_id
and self
.pool
.get("res.partner")._find
_accounting
_partner
(order
.partner_id
).id or False
210 # Create a move for each tax group
211 (tax_code_pos
, base_code_pos
, account_pos
, tax_id
)= (0, 1, 2, 3)
213 for key
, tax_amount
in group_tax
.items():
214 tax
= self
.pool
.get('account.tax').browse(cr
, uid
, key
[tax_id
], context
=context
)
216 'name': _('Tax') + ' ' + tax
.name
,
217 'quantity': line
.qty
,
218 'product_id': line
.product_id
.id,
219 'account_id': key
[account_pos
] or income_account
,
220 'credit': ((tax_amount
>0) and tax_amount
) or 0.0,
221 'debit': ((tax_amount
<0) and -tax_amount
) or 0.0,
222 'tax_code_id': key
[tax_code_pos
],
223 'tax_amount': tax_amount
,
224 'partner_id': order
.partner_id
and self
.pool
.get("res.partner")._find
_accounting
_partner
(order
.partner_id
).id or False
228 insert_data('counter_part', {
229 'name': _("Trade Receivables"), #order.name,
230 'account_id': order_account
,
231 'credit': ((order
.amount_total
< 0) and -order
.amount_total
) or 0.0,
232 'debit': ((order
.amount_total
> 0) and order
.amount_total
) or 0.0,
233 'partner_id': order
.partner_id
and self
.pool
.get("res.partner")._find
_accounting
_partner
(order
.partner_id
).id or False
236 order
.write({'state':'done', 'account_move': move_id
})
239 for group_key
, group_data
in grouped_data
.iteritems():
240 print("#DEBUG: group_key = %s - group_data = %s" % (group_key
, group_data
))
241 for value
in group_data
:
242 all_lines
.append((0, 0, value
),)
243 if move_id
: #In case no order was changed
244 self
.pool
.get("account.move").write(cr
, uid
, [move_id
], {'line_id':all_lines
}, context
=context
)
248 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: