Merge lp:~julie-w/unifield-server/US-6076 into lp:unifield-server
- US-6076
- Merge into trunk
Proposed by
jftempo
Status: | Merged |
---|---|
Merged at revision: | 5440 |
Proposed branch: | lp:~julie-w/unifield-server/US-6076 |
Merge into: | lp:unifield-server |
Diff against target: |
2105 lines (+1121/-125) 22 files modified
bin/addons/account/account_invoice_view.xml (+99/-35) bin/addons/account/invoice.py (+55/-13) bin/addons/account/wizard/account_invoice_refund.py (+36/-7) bin/addons/account/wizard/account_invoice_refund_view.xml (+4/-1) bin/addons/account_override/__init__.py (+1/-0) bin/addons/account_override/account_invoice_sync.py (+362/-0) bin/addons/account_override/account_invoice_view.xml (+119/-24) bin/addons/account_override/invoice.py (+103/-11) bin/addons/analytic_distribution/account_invoice_refund.py (+26/-5) bin/addons/analytic_distribution/account_invoice_view.xml (+8/-2) bin/addons/msf_audittrail/audittrail_invoice_data.yml (+2/-1) bin/addons/msf_outgoing/msf_outgoing.py (+2/-0) bin/addons/msf_profile/data/patches.xml (+5/-0) bin/addons/msf_profile/i18n/fr_MF.po (+244/-15) bin/addons/msf_profile/msf_profile.py (+15/-0) bin/addons/msf_sync_data_server/data/sync_server.message_rule.csv (+4/-0) bin/addons/purchase/purchase_workflow.py (+3/-3) bin/addons/register_accounting/account_invoice_view.xml (+14/-2) bin/addons/sale/sale_workflow.py (+3/-3) bin/addons/stock/stock.py (+8/-0) bin/addons/stock_override/stock.py (+5/-0) bin/addons/sync_so/picking.py (+3/-3) |
To merge this branch: | bzr merge lp:~julie-w/unifield-server/US-6076 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
UniField Reviewer Team | Pending | ||
Review via email: mp+370103@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'bin/addons/account/account_invoice_view.xml' |
2 | --- bin/addons/account/account_invoice_view.xml 2018-02-13 15:48:51 +0000 |
3 | +++ bin/addons/account/account_invoice_view.xml 2019-07-15 07:18:58 +0000 |
4 | @@ -53,11 +53,29 @@ |
5 | <form string="Invoice Line"> |
6 | <notebook> |
7 | <page string="Line"> |
8 | - <field name="product_id" on_change="product_id_change(product_id, uos_id, quantity, name, parent.type, parent.partner_id, parent.fiscal_position, price_unit, parent.address_invoice_id, parent.currency_id, {'company_id': parent.company_id})" default_focus="1"/> |
9 | - <field name="uos_id" on_change="uos_id_change(product_id, uos_id, quantity, name, parent.type, parent.partner_id, parent.fiscal_position, price_unit, parent.address_invoice_id, parent.currency_id, {'company_id': parent.company_id})"/> |
10 | - <field name="quantity"/> |
11 | - <field name="price_unit"/> |
12 | - <field name="discount" groups="base.group_extended"/> |
13 | + <field name="invoice_type" invisible="1"/> |
14 | + <field name="from_supply" invisible="1"/> |
15 | + <field name="partner_type" invisible="1"/> |
16 | + <field name="product_id" |
17 | + on_change="product_id_change(product_id, uos_id, quantity, name, parent.type, parent.partner_id, parent.fiscal_position, price_unit, parent.address_invoice_id, parent.currency_id, {'company_id': parent.company_id})" |
18 | + default_focus="1" |
19 | + attrs="{'readonly': ['|', |
20 | + '&', ('invoice_type', '=', 'in_invoice'), ('synced', '=', True), |
21 | + '&', '&', ('invoice_type', '=', 'out_invoice'), ('from_supply', '=', True), ('partner_type', 'in', ('intermission', 'section'))]}" |
22 | + /> |
23 | + <field name="uos_id" |
24 | + on_change="uos_id_change(product_id, uos_id, quantity, name, parent.type, parent.partner_id, parent.fiscal_position, price_unit, parent.address_invoice_id, parent.currency_id, {'company_id': parent.company_id})" |
25 | + attrs="{'readonly': ['|', |
26 | + '&', ('invoice_type', '=', 'in_invoice'), ('synced', '=', True), |
27 | + '&', '&', ('invoice_type', '=', 'out_invoice'), ('from_supply', '=', True), ('partner_type', 'in', ('intermission', 'section'))]}" |
28 | + /> |
29 | + <field name="quantity" attrs="{'readonly': ['|', |
30 | + '&', ('invoice_type', '=', 'in_invoice'), ('synced', '=', True), |
31 | + '&', '&', ('invoice_type', '=', 'out_invoice'), ('from_supply', '=', True), ('partner_type', 'in', ('intermission', 'section'))]}" |
32 | + /> |
33 | + <field name="price_unit" attrs="{'readonly': [('invoice_type', '=', 'in_invoice'), ('synced', '=', True)]}"/> |
34 | + <field name="discount" groups="base.group_extended" |
35 | + attrs="{'readonly': [('invoice_type', '=', 'in_invoice'), ('synced', '=', True)]}"/> |
36 | <field colspan="4" name="name"/> |
37 | <field domain="[('company_id', '=', parent.company_id), ('journal_id', '=', parent.journal_id), ('type', '<>', 'view')]" name="account_id"/> |
38 | <field domain="[('type','<>','view'), ('company_id', '=', parent.company_id), ('parent_id', '!=', False)]" name="account_analytic_id" groups="analytic.group_analytic_accounting"/> |
39 | @@ -152,10 +170,17 @@ |
40 | <field name="journal_id" widget="selection"/> |
41 | <field name="number" readonly="1"/> |
42 | <field name="type" invisible="1"/> |
43 | - <field name="currency_id" width="50"/> |
44 | - <button name="%(action_account_change_currency)d" type="action" icon="terp-stock_effects-object-colorize" string="Change" attrs="{'invisible':[('state','!=','draft')]}" groups="account.group_account_user"/> |
45 | + <field name="currency_id" width="50" attrs="{'readonly': [('type', '=', 'in_invoice'), ('synced', '=', True)]}"/> |
46 | + <button name="%(action_account_change_currency)d" type="action" icon="terp-stock_effects-object-colorize" |
47 | + string="Change" groups="account.group_account_user" |
48 | + attrs="{'invisible':[('state', '!=', 'draft')], |
49 | + 'readonly': [('type', '=', 'in_invoice'), ('synced', '=', True)]}"/> |
50 | <newline/> |
51 | - <field string="Supplier" name="partner_id" domain="[('supplier', '=', True)]" on_change="onchange_partner_id(type,partner_id,date_invoice,payment_term, partner_bank_id,company_id)" context="{'default_customer': 0, 'search_default_supplier': 1, 'default_supplier': 1}"/> |
52 | + <field string="Supplier" name="partner_id" domain="[('supplier', '=', True)]" |
53 | + on_change="onchange_partner_id(type, partner_id, date_invoice, payment_term, partner_bank_id, company_id)" |
54 | + context="{'default_customer': 0, 'search_default_supplier': 1, 'default_supplier': 1}" |
55 | + attrs="{'readonly': [('type', '=', 'in_invoice'), ('synced', '=', True)]}" |
56 | + /> |
57 | <field domain="[('partner_id','=',partner_id)]" name="address_invoice_id"/> |
58 | <field name="fiscal_position" groups="base.group_extended" widget="selection"/> |
59 | <newline/> |
60 | @@ -187,25 +212,39 @@ |
61 | </tree> |
62 | </field> |
63 | <group col="1" colspan="2"> |
64 | - <field name="tax_line" nolabel="1"> |
65 | - <tree editable="bottom" string="Taxes"> |
66 | - <field name="invoice_id" invisible="True"/> |
67 | - <field name="account_tax_id" on_change="tax_code_change(account_tax_id,parent.amount_untaxed,context)"/> |
68 | - <field name="name"/> |
69 | - |
70 | - <field name="account_id" groups="account.group_account_invoice" |
71 | - domain="[('type', 'not in', ['view', 'consolidation']), |
72 | - ('user_type_code', '=', 'tax')]"/> |
73 | - |
74 | - <field name="base" on_change="base_change(base,parent.currency_id,parent.company_id,parent.date_invoice)" readonly="1"/> |
75 | - <field name="amount" on_change="amount_change(amount,parent.currency_id,parent.company_id,parent.date_invoice)"/> |
76 | - |
77 | - <field invisible="True" name="base_amount"/> |
78 | - <field invisible="True" name="tax_amount"/> |
79 | - <field name="factor_base" invisible="True"/> |
80 | - <field name="factor_tax" invisible="True"/> |
81 | - </tree> |
82 | - </field> |
83 | + <group colspan="1" attrs="{'invisible': ['|', ('type', '!=', 'in_invoice'), ('synced', '=', False)]}"> |
84 | + <!-- SI synced: Tax Lines always in read-only --> |
85 | + <field name="tax_line_ids" nolabel="1"> |
86 | + <tree noteditable="1" string="Taxes"> |
87 | + <field name="account_tax_id"/> |
88 | + <field name="name"/> |
89 | + <field name="account_id"/> |
90 | + <field name="base"/> |
91 | + <field name="amount"/> |
92 | + </tree> |
93 | + </field> |
94 | + </group> |
95 | + <group colspan="1" attrs="{'invisible': [('type', '=', 'in_invoice'), ('synced', '=', True)]}"> |
96 | + <field name="tax_line" nolabel="1"> |
97 | + <tree editable="bottom" string="Taxes"> |
98 | + <field name="invoice_id" invisible="True"/> |
99 | + <field name="account_tax_id" on_change="tax_code_change(account_tax_id,parent.amount_untaxed,context)"/> |
100 | + <field name="name"/> |
101 | + |
102 | + <field name="account_id" groups="account.group_account_invoice" |
103 | + domain="[('type', 'not in', ['view', 'consolidation']), |
104 | + ('user_type_code', '=', 'tax')]"/> |
105 | + |
106 | + <field name="base" on_change="base_change(base,parent.currency_id,parent.company_id,parent.date_invoice)" readonly="1"/> |
107 | + <field name="amount" on_change="amount_change(amount,parent.currency_id,parent.company_id,parent.date_invoice)"/> |
108 | + |
109 | + <field invisible="True" name="base_amount"/> |
110 | + <field invisible="True" name="tax_amount"/> |
111 | + <field name="factor_base" invisible="True"/> |
112 | + <field name="factor_tax" invisible="True"/> |
113 | + </tree> |
114 | + </field> |
115 | + </group> |
116 | </group> |
117 | <group col="4" colspan="2"> |
118 | <button colspan="2" name="button_reset_taxes" states="draft" string="Compute Taxes" type="object" icon="terp-stock_format-scientific"/> |
119 | @@ -230,11 +269,14 @@ |
120 | <field name="company_id" on_change="onchange_company_id(company_id,partner_id,type,invoice_line,currency_id)" widget="selection" groups="base.group_multi_company"/> |
121 | <newline/> |
122 | <field name="payment_term" widget="selection"/> |
123 | - <field name="name"/> |
124 | + <field name="name" |
125 | + attrs="{'readonly': [('type', '=', 'in_invoice'), ('synced', '=', True), ('from_supply', '=', True)]}"/> |
126 | <newline/> |
127 | - <field name="origin" groups="base.group_extended"/> |
128 | + <field name="origin" groups="base.group_extended" |
129 | + attrs="{'readonly': [('type', '=', 'in_invoice'), ('synced', '=', True), ('from_supply', '=', True)]}"/> |
130 | <field domain="[('partner_id','=',partner_id)]" name="address_contact_id" groups="base.group_extended"/> |
131 | - <field name="user_id"/> |
132 | + <field name="user_id" |
133 | + attrs="{'readonly': [('type', '=', 'in_invoice'), ('synced', '=', True)]}"/> |
134 | <field name="move_id" groups="account.group_account_user"/> |
135 | <separator colspan="4" string="Additional Information"/> |
136 | <field colspan="4" name="comment" nolabel="1"/> |
137 | @@ -273,7 +315,13 @@ |
138 | <field name="currency_id" width="50"/> |
139 | <button name="%(action_account_change_currency)d" type="action" icon="terp-stock_effects-object-colorize" string="Change" attrs="{'invisible':[('state','!=','draft')]}" groups="account.group_account_user"/> |
140 | <newline/> |
141 | - <field string="Customer" name="partner_id" domain="[('customer', '=', True)]" on_change="onchange_partner_id(type,partner_id,date_invoice,payment_term, partner_bank_id,company_id)" groups="base.group_user" context="{'search_default_customer': 1}"/> |
142 | + <field string="Customer" name="partner_id" |
143 | + domain="[('customer', '=', True)]" |
144 | + on_change="onchange_partner_id(type,partner_id,date_invoice,payment_term, partner_bank_id,company_id)" |
145 | + groups="base.group_user" context="{'search_default_customer': 1}" |
146 | + attrs="{'readonly': [('type', '=', 'out_invoice'), |
147 | + ('from_supply', '=', True), |
148 | + ('partner_type', 'in', ('intermission', 'section'))]}"/> |
149 | <field domain="[('partner_id','=',partner_id)]" name="address_invoice_id"/> |
150 | <field name="fiscal_position" groups="base.group_extended" widget="selection"/> |
151 | <newline/> |
152 | @@ -286,9 +334,11 @@ |
153 | <notebook colspan="4"> |
154 | <page string="Invoice"> |
155 | <field domain="[('company_id', '=', company_id),('type','=', 'receivable')]" name="account_id" groups="account.group_account_user"/> |
156 | - <field name="name"/> |
157 | + <field name="name" attrs="{'readonly': [('type', '=', 'out_invoice'), |
158 | + ('from_supply', '=', True), |
159 | + ('partner_type', 'in', ('intermission', 'section'))]}"/> |
160 | <field name="payment_term" widget="selection"/> |
161 | - <field colspan="4" name="invoice_line" nolabel="1" widget="one2many_list" context="{'fake':1}"/> |
162 | + <field colspan="4" name="invoice_line" nolabel="1" widget="one2many_list" context="{'fake': 1, 'from_inv_form': True}"/> |
163 | <group col="1" colspan="2"> |
164 | <field name="tax_line" nolabel="1"> |
165 | <tree editable="bottom" string="Taxes"> |
166 | @@ -328,11 +378,15 @@ |
167 | <field name="company_id" on_change="onchange_company_id(company_id,partner_id,type,invoice_line,currency_id)" widget="selection" groups="base.group_multi_company"/> |
168 | <newline/> |
169 | <field name="date_due"/> |
170 | - <field name="user_id"/> |
171 | + <field name="user_id" attrs="{'readonly': [('type', '=', 'out_invoice'), |
172 | + ('from_supply', '=', True), |
173 | + ('partner_type', 'in', ('intermission', 'section'))]}"/> |
174 | <newline/> |
175 | <field domain="[('partner_id.ref_companies', 'in', [company_id])]" name="partner_bank_id" |
176 | groups="base.group_extended"/> |
177 | - <field name="origin"/> |
178 | + <field name="origin" attrs="{'readonly': [('type', '=', 'out_invoice'), |
179 | + ('from_supply', '=', True), |
180 | + ('partner_type', 'in', ('intermission', 'section'))]}"/> |
181 | <field colspan="4" domain="[('partner_id','=',partner_id)]" name="address_contact_id" |
182 | groups="base.group_extended"/> |
183 | <field name="move_id" groups="account.group_account_user"/> |
184 | @@ -353,6 +407,16 @@ |
185 | </tree> |
186 | </field> |
187 | </page> |
188 | + <!-- display the Counterpart Invoice tab in STV, hide it in Customer Refunds --> |
189 | + <page string="Counterpart Invoice" attrs="{'invisible': [('type', '!=', 'out_invoice')]}"> |
190 | + <field name="from_supply" invisible="1"/> |
191 | + <field name="synced" |
192 | + attrs="{'readonly': ['|', ('from_supply', '=', True), ('state', '!=', 'draft')]}" |
193 | + on_change="onchange_synced(synced, partner_id)"/> |
194 | + <newline/> |
195 | + <field name="counterpart_inv_number"/> |
196 | + <field name="counterpart_inv_status"/> |
197 | + </page> |
198 | </notebook> |
199 | </form> |
200 | </field> |
201 | |
202 | === modified file 'bin/addons/account/invoice.py' |
203 | --- bin/addons/account/invoice.py 2019-06-05 09:09:37 +0000 |
204 | +++ bin/addons/account/invoice.py 2019-07-15 07:18:58 +0000 |
205 | @@ -26,6 +26,7 @@ |
206 | import netsvc |
207 | from osv import fields, osv, orm |
208 | from tools.translate import _ |
209 | +from msf_partner import PARTNER_TYPE |
210 | |
211 | |
212 | class account_invoice(osv.osv): |
213 | @@ -257,7 +258,7 @@ |
214 | _order = "id desc" |
215 | |
216 | _columns = { |
217 | - 'name': fields.char('Description', size=64, select=True, readonly=True, states={'draft':[('readonly',False)]}), |
218 | + 'name': fields.char('Description', size=256, select=True, readonly=True, states={'draft': [('readonly', False)]}), |
219 | 'origin': fields.char('Source Document', size=512, help="Reference of the document that produced this invoice.", readonly=True, states={'draft':[('readonly',False)]}), |
220 | 'type': fields.selection([ |
221 | ('out_invoice','Customer Invoice'), |
222 | @@ -302,7 +303,8 @@ |
223 | 'account_id': fields.many2one('account.account', 'Account', required=True, readonly=True, states={'draft':[('readonly',False)]}, help="The partner account used for this invoice."), |
224 | 'invoice_line': fields.one2many('account.invoice.line', 'invoice_id', 'Invoice Lines', readonly=True, states={'draft':[('readonly',False)]}), |
225 | 'tax_line': fields.one2many('account.invoice.tax', 'invoice_id', 'Tax Lines', readonly=True, states={'draft':[('readonly',False)]}), |
226 | - |
227 | + 'tax_line_ids': fields.related('tax_line', type='one2many', relation='account.invoice.tax', string='Tax Lines', |
228 | + readonly=True, store=False, help="Internal field for taxes always in read-only mode"), |
229 | 'move_id': fields.many2one('account.move', 'Journal Entry', readonly=True, select=1, ondelete='restrict', help="Link to the automatically generated Journal Items."), |
230 | 'amount_untaxed': fields.function(_amount_all, method=True, digits_compute=dp.get_precision('Account'), string='Untaxed', |
231 | store={ |
232 | @@ -463,13 +465,17 @@ |
233 | def unlink(self, cr, uid, ids, context=None): |
234 | if context is None: |
235 | context = {} |
236 | - invoices = self.read(cr, uid, ids, ['state'], context=context) |
237 | + invoices = self.read(cr, uid, ids, ['state', 'synced', 'from_supply'], context=context) |
238 | unlink_ids = [] |
239 | for t in invoices: |
240 | - if t['state'] in ('draft', 'cancel'): |
241 | + if t['state'] not in ('draft', 'cancel'): |
242 | + raise osv.except_osv(_('Invalid action !'), _('Cannot delete invoice(s) that are already opened or paid !')) |
243 | + elif t['from_supply']: |
244 | + raise osv.except_osv(_('Invalid action !'), _('Cannot delete invoice(s) generated by a Supply workflow!')) |
245 | + elif t['synced']: |
246 | + raise osv.except_osv(_('Invalid action !'), _('Cannot delete invoice(s) set as "Synchronized"!')) |
247 | + else: |
248 | unlink_ids.append(t['id']) |
249 | - else: |
250 | - raise osv.except_osv(_('Invalid action !'), _('Cannot delete invoice(s) that are already opened or paid !')) |
251 | osv.osv.unlink(self, cr, uid, unlink_ids, context=context) |
252 | return True |
253 | |
254 | @@ -481,6 +487,7 @@ |
255 | acc_id = False |
256 | bank_id = False |
257 | fiscal_position = False |
258 | + partner_type = False |
259 | |
260 | opt = [('uid', str(uid))] |
261 | if partner_id: |
262 | @@ -490,6 +497,8 @@ |
263 | contact_addr_id = res['contact'] |
264 | invoice_addr_id = res['invoice'] |
265 | p = self.pool.get('res.partner').browse(cr, uid, partner_id) |
266 | + partner_type = p.partner_type # update the partner type immediately as it is used in a domain in attrs |
267 | + |
268 | if company_id: |
269 | if p.property_account_receivable.company_id.id != company_id and p.property_account_payable.company_id.id != company_id: |
270 | property_obj = self.pool.get('ir.property') |
271 | @@ -526,7 +535,8 @@ |
272 | 'address_invoice_id': invoice_addr_id, |
273 | 'account_id': acc_id, |
274 | 'payment_term': partner_payment_term, |
275 | - 'fiscal_position': fiscal_position |
276 | + 'fiscal_position': fiscal_position, |
277 | + 'partner_type': partner_type, |
278 | } |
279 | } |
280 | |
281 | @@ -662,6 +672,22 @@ |
282 | val['currency_id'] = currency.id |
283 | return {'value': val, 'domain': dom} |
284 | |
285 | + def onchange_synced(self, cr, uid, ids, synced, partner_id): |
286 | + """ |
287 | + Resets "synced" field and informs the user in case the box is ticked whereas the partner is neither Intermission nor Intersection |
288 | + """ |
289 | + res = {} |
290 | + partner_obj = self.pool.get('res.partner') |
291 | + if synced and partner_id: |
292 | + if partner_obj.browse(cr, uid, partner_id, fields_to_fetch=['partner_type']).partner_type not in ('intermission', 'section'): |
293 | + warning = { |
294 | + 'title': _('Warning!'), |
295 | + 'message': _('Synchronization is allowed only with Intermission and Intersection partners.') |
296 | + } |
297 | + res['warning'] = warning |
298 | + res['value'] = {'synced': False, } |
299 | + return res |
300 | + |
301 | # go from canceled state to draft state |
302 | def action_cancel_draft(self, cr, uid, ids, *args): |
303 | self.write(cr, uid, ids, {'state':'draft'}) |
304 | @@ -705,6 +731,10 @@ |
305 | 'move_name':False, |
306 | 'internal_number': False, |
307 | 'main_purchase_id': False, |
308 | + 'from_supply': False, |
309 | + 'synced': False, |
310 | + 'counterpart_inv_number': False, |
311 | + 'counterpart_inv_status': False, |
312 | }) |
313 | if 'date_invoice' not in default: |
314 | default.update({ |
315 | @@ -1324,12 +1354,18 @@ |
316 | for invoice in invoices: |
317 | del invoice['id'] |
318 | |
319 | - type_dict = { |
320 | - 'out_invoice': 'out_refund', # Customer Invoice |
321 | - 'in_invoice': 'in_refund', # Supplier Invoice |
322 | - 'out_refund': 'out_invoice', # Customer Refund |
323 | - 'in_refund': 'in_invoice', # Supplier Refund |
324 | - } |
325 | + if context.get('is_intermission', False): |
326 | + type_dict = { |
327 | + 'out_invoice': 'in_invoice', # IVO |
328 | + 'in_invoice': 'out_invoice', # IVI |
329 | + } |
330 | + else: |
331 | + type_dict = { |
332 | + 'out_invoice': 'out_refund', # Customer Invoice |
333 | + 'in_invoice': 'in_refund', # Supplier Invoice |
334 | + 'out_refund': 'out_invoice', # Customer Refund |
335 | + 'in_refund': 'in_invoice', # Supplier Refund |
336 | + } |
337 | |
338 | invoice_lines = obj_invoice_line.read(cr, uid, invoice['invoice_line']) |
339 | invoice_lines = self._refund_cleanup_lines(cr, uid, invoice_lines, is_account_inv_line=True, context=context) |
340 | @@ -1355,6 +1391,10 @@ |
341 | 'journal_id': refund_journal_ids, |
342 | 'origin': invoice['number'] |
343 | }) |
344 | + if context.get('is_intermission', False): |
345 | + invoice.update({ |
346 | + 'is_intermission': True, |
347 | + }) |
348 | if period_id: |
349 | invoice.update({ |
350 | 'period_id': period_id, |
351 | @@ -1515,6 +1555,8 @@ |
352 | 'name': fields.char('Description', size=256, required=True), |
353 | 'origin': fields.char('Origin', size=512, help="Reference of the document that produced this invoice."), |
354 | 'invoice_id': fields.many2one('account.invoice', 'Invoice Reference', ondelete='cascade', select=True), |
355 | + 'partner_type': fields.related('invoice_id', 'partner_type', string='Partner Type', type='selection', |
356 | + selection=PARTNER_TYPE, readonly=True, store=False), |
357 | 'uos_id': fields.many2one('product.uom', 'Unit of Measure', ondelete='set null'), |
358 | 'product_id': fields.many2one('product.product', 'Product', ondelete='set null'), |
359 | 'account_id': fields.many2one('account.account', 'Account', required=True, domain=[('type','<>','view'), ('type', '<>', 'closed')], help="The income or expense account related to the selected product."), |
360 | |
361 | === modified file 'bin/addons/account/wizard/account_invoice_refund.py' |
362 | --- bin/addons/account/wizard/account_invoice_refund.py 2018-05-14 12:41:04 +0000 |
363 | +++ bin/addons/account/wizard/account_invoice_refund.py 2019-07-15 07:18:58 +0000 |
364 | @@ -29,13 +29,24 @@ |
365 | |
366 | _name = "account.invoice.refund" |
367 | _description = "Invoice Refund" |
368 | + |
369 | + def _get_filter_refund(self, cr, uid, context=None): |
370 | + """ |
371 | + Returns the selectable Refund Types (no simple "Refund" in case of an IVO/IVI) |
372 | + """ |
373 | + if context is None: |
374 | + context = {} |
375 | + if context.get('is_intermission', False): |
376 | + return [('modify', 'Modify'), ('cancel', 'Cancel')] |
377 | + return [('modify', 'Modify'), ('refund', 'Refund'), ('cancel', 'Cancel')] |
378 | + |
379 | _columns = { |
380 | 'date': fields.date('Operation date', help='This date will be used as the invoice date for Refund Invoice and Period will be chosen accordingly!'), |
381 | 'period': fields.many2one('account.period', 'Force period'), |
382 | 'journal_id': fields.many2one('account.journal', 'Refund Journal', hide_default_menu=True, |
383 | help='You can select here the journal to use for the refund invoice that will be created. If you leave that field empty, it will use the same journal as the current invoice.'), |
384 | 'description': fields.char('Description', size=128, required=True), |
385 | - 'filter_refund': fields.selection([('modify', 'Modify'), ('refund', 'Refund'), ('cancel', 'Cancel')], "Refund Type", required=True, help='Refund invoice base on this type. You can not Modify and Cancel if the invoice is already reconciled'), |
386 | + 'filter_refund': fields.selection(_get_filter_refund, "Refund Type", required=True, help='Refund invoice based on this type. You can not Modify and Cancel if the invoice is already reconciled'), |
387 | } |
388 | |
389 | def _get_journal(self, cr, uid, context=None): |
390 | @@ -145,7 +156,10 @@ |
391 | if inv.state in ['draft', 'proforma2', 'cancel']: |
392 | raise osv.except_osv(_('Error !'), _('Can not %s draft/proforma/cancel invoice.') % (mode)) |
393 | if mode in ('cancel', 'modify') and inv_obj.has_one_line_reconciled(cr, uid, [inv.id], context=context): |
394 | - raise osv.except_osv(_('Error !'), _('Can not %s invoice which is already reconciled, invoice should be unreconciled first. You can only Refund this invoice') % (mode)) |
395 | + if inv.is_intermission: |
396 | + # error specific to IVO/IVI for which there is no simple refund option |
397 | + raise osv.except_osv(_('Error !'), _('Cannot %s an Intermission Voucher which is already reconciled, it should be unreconciled first.') % _(mode)) |
398 | + raise osv.except_osv(_('Error !'), _('Can not %s invoice which is already reconciled, invoice should be unreconciled first. You can only Refund this invoice') % _(mode)) |
399 | if form['period']: |
400 | period = form['period'] |
401 | else: |
402 | @@ -188,8 +202,14 @@ |
403 | refund_id = self._hook_create_refund(cr, uid, [inv.id], date, period, description, journal_id, form, context=context) |
404 | del context['refund_mode'] # ignore it for the remaining process (in particular for the SI created in a refund modify...) |
405 | refund = inv_obj.browse(cr, uid, refund_id[0], context=context) |
406 | + # for Intermission Vouchers OUT: at standard creation time there is no "check_total" entered manually, |
407 | + # its value is always 0.0 => use the "amount_total" value for the IVI generated so it won't block at validation step |
408 | + if inv.is_intermission and inv.type == 'out_invoice': |
409 | + check_total = inv.amount_total or 0.0 |
410 | + else: |
411 | + check_total = inv.check_total |
412 | inv_obj.write(cr, uid, [refund.id], {'date_due': date, |
413 | - 'check_total': inv.check_total}) |
414 | + 'check_total': check_total}) |
415 | |
416 | created_inv.append(refund_id[0]) |
417 | if mode in ('cancel', 'modify'): |
418 | @@ -230,6 +250,7 @@ |
419 | 'period_id': False, |
420 | 'name': description, |
421 | 'origin': source_doc, |
422 | + 'is_intermission': inv.is_intermission, |
423 | }) |
424 | for field in self._hook_fields_m2o_for_modify_refund(cr, uid): |
425 | invoice[field] = invoice[field] and invoice[field][0] |
426 | @@ -254,11 +275,19 @@ |
427 | # write on JIs without recreating AJIs |
428 | account_m_line_obj.write(cr, uid, ji_ids, {'is_si_refund': True}, context=context, check=False, update_check=False) |
429 | |
430 | - if inv.type in ('out_invoice', 'out_refund'): |
431 | - xml_id = 'action_invoice_tree3' |
432 | + if context.get('is_intermission', False): |
433 | + module = 'account_override' |
434 | + if inv.type == 'in_invoice': |
435 | + xml_id = 'action_intermission_out' |
436 | + else: |
437 | + xml_id = 'action_intermission_in' |
438 | else: |
439 | - xml_id = 'action_invoice_tree4' |
440 | - result = mod_obj.get_object_reference(cr, uid, 'account', xml_id) |
441 | + module = 'account' |
442 | + if inv.type in ('out_invoice', 'out_refund'): |
443 | + xml_id = 'action_invoice_tree3' |
444 | + else: |
445 | + xml_id = 'action_invoice_tree4' |
446 | + result = mod_obj.get_object_reference(cr, uid, module, xml_id) |
447 | id = result and result[1] or False |
448 | result = act_obj.read(cr, uid, id, context=context) |
449 | invoice_domain = eval(result['domain']) |
450 | |
451 | === modified file 'bin/addons/account/wizard/account_invoice_refund_view.xml' |
452 | --- bin/addons/account/wizard/account_invoice_refund_view.xml 2018-05-15 08:55:26 +0000 |
453 | +++ bin/addons/account/wizard/account_invoice_refund_view.xml 2019-07-15 07:18:58 +0000 |
454 | @@ -15,11 +15,14 @@ |
455 | <field name="date" required="1"/> |
456 | <field name="period"/> |
457 | <field name="filter_refund"/> |
458 | + <field name="is_intermission" invisible="1"/> |
459 | </group> |
460 | <separator colspan="4"/> |
461 | <group col="4" colspan="4" fill="1"> |
462 | <label align="0.0" width="550" colspan="4" string="Modify Invoice: Cancels the current invoice and creates a new copy of it ready for editing."/> |
463 | - <label align="0.0" width="300" string="Refund Invoice: Creates the refund invoice, ready for editing."/> |
464 | + <group attrs="{'invisible': [('is_intermission', '=', True)] }"> |
465 | + <label align="0.0" width="300" string="Refund Invoice: Creates the refund invoice, ready for editing."/> |
466 | + </group> |
467 | <label align="0.0" width="500" colspan="4" string="Cancel Invoice: Creates the refund invoice, validate and reconcile it to cancel the current invoice."/> |
468 | </group> |
469 | <separator colspan="4"/> |
470 | |
471 | === modified file 'bin/addons/account_override/__init__.py' |
472 | --- bin/addons/account_override/__init__.py 2019-01-08 11:20:04 +0000 |
473 | +++ bin/addons/account_override/__init__.py 2019-07-15 07:18:58 +0000 |
474 | @@ -230,4 +230,5 @@ |
475 | import report |
476 | import wizard |
477 | import finance_export |
478 | +import account_invoice_sync |
479 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
480 | |
481 | === added file 'bin/addons/account_override/account_invoice_sync.py' |
482 | --- bin/addons/account_override/account_invoice_sync.py 1970-01-01 00:00:00 +0000 |
483 | +++ bin/addons/account_override/account_invoice_sync.py 2019-07-15 07:18:58 +0000 |
484 | @@ -0,0 +1,362 @@ |
485 | +#!/usr/bin/env python |
486 | +#-*- encoding:utf-8 -*- |
487 | +############################################################################## |
488 | +# |
489 | +# OpenERP, Open Source Management Solution |
490 | +# Copyright (C) 2019 TeMPO Consulting, MSF. All Rights Reserved |
491 | +# |
492 | +# This program is free software: you can redistribute it and/or modify |
493 | +# it under the terms of the GNU Affero General Public License as |
494 | +# published by the Free Software Foundation, either version 3 of the |
495 | +# License, or (at your option) any later version. |
496 | +# |
497 | +# This program is distributed in the hope that it will be useful, |
498 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
499 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
500 | +# GNU Affero General Public License for more details. |
501 | +# |
502 | +# You should have received a copy of the GNU Affero General Public License |
503 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
504 | +# |
505 | +############################################################################## |
506 | + |
507 | + |
508 | +from osv import osv |
509 | +from osv import fields |
510 | +from tools.translate import _ |
511 | +import logging |
512 | +import time |
513 | + |
514 | + |
515 | +class account_invoice_sync(osv.osv): |
516 | + _inherit = 'account.invoice' |
517 | + _logger = logging.getLogger('------sync.account.invoice') |
518 | + |
519 | + _columns = { |
520 | + 'synced': fields.boolean("Synchronized"), |
521 | + 'from_supply': fields.boolean('From Supply', help="Internal field indicating whether the document is related to a Supply workflow"), |
522 | + 'counterpart_inv_number': fields.char('Counterpart Invoice Number', size=64, readonly=True), |
523 | + 'counterpart_inv_status': fields.selection([ |
524 | + ('draft', 'Draft'), |
525 | + ('open', 'Open'), |
526 | + ('paid', 'Paid'), |
527 | + ('cancel', 'Cancelled'), |
528 | + ], string='Counterpart Invoice Status', readonly=True), |
529 | + } |
530 | + |
531 | + _defaults = { |
532 | + 'synced': lambda *a: False, |
533 | + 'from_supply': lambda *a: False, |
534 | + } |
535 | + |
536 | + def _create_analytic_distrib(self, cr, uid, vals, distrib, context=None): |
537 | + """ |
538 | + Updates vals with the new analytic_distribution_id created based on the distrib in parameter if it exists |
539 | + """ |
540 | + if context is None: |
541 | + context = {} |
542 | + analytic_distrib_obj = self.pool.get('analytic.distribution') |
543 | + cc_distrib_line_obj = self.pool.get('cost.center.distribution.line') |
544 | + fp_distrib_line_obj = self.pool.get('funding.pool.distribution.line') |
545 | + data_obj = self.pool.get('ir.model.data') |
546 | + # get the Funding Pool "PF" |
547 | + try: |
548 | + fp_id = data_obj.get_object_reference(cr, uid, 'analytic_distribution', 'analytic_account_msf_private_funds')[1] |
549 | + except ValueError: |
550 | + fp_id = 0 |
551 | + if distrib: # original distrib from PO or PO line |
552 | + # create the Analytic Distribution |
553 | + distrib_id = analytic_distrib_obj.create(cr, uid, {}, context=context) |
554 | + for cc_line in distrib.cost_center_lines: |
555 | + distrib_vals = { |
556 | + 'analytic_id': cc_line.analytic_id and cc_line.analytic_id.id, # analytic_id = Cost Center for the CC distrib line |
557 | + 'percentage': cc_line.percentage or 0.0, |
558 | + 'distribution_id': distrib_id, |
559 | + 'currency_id': cc_line.currency_id.id, |
560 | + 'destination_id': cc_line.destination_id.id, |
561 | + } |
562 | + cc_distrib_line_obj.create(cr, uid, distrib_vals, context=context) |
563 | + distrib_vals.update({ |
564 | + 'analytic_id': fp_id, # analytic_id = Funding Pool for the FP distrib line |
565 | + 'cost_center_id': cc_line.analytic_id and cc_line.analytic_id.id, |
566 | + }) |
567 | + fp_distrib_line_obj.create(cr, uid, distrib_vals, context=context) |
568 | + vals.update({'analytic_distribution_id': distrib_id,}) |
569 | + |
570 | + def _create_invoice_lines(self, cr, uid, inv_lines_data, inv_id, inv_posting_date, inv_linked_po, from_supply, context=None): |
571 | + """ |
572 | + Creates the lines of the automatic counterpart invoice (inv_id) generated at synchro time. |
573 | + """ |
574 | + if context is None: |
575 | + context = {} |
576 | + so_po_common_obj = self.pool.get('so.po.common') |
577 | + product_obj = self.pool.get('product.product') |
578 | + account_obj = self.pool.get('account.account') |
579 | + product_uom_obj = self.pool.get('product.uom') |
580 | + inv_line_obj = self.pool.get('account.invoice.line') |
581 | + for inv_line in inv_lines_data: |
582 | + line_name = inv_line.get('name', '') |
583 | + if not line_name: # required field |
584 | + raise osv.except_osv(_('Error'), _("Impossible to retrieve the line description.")) |
585 | + product_id = False |
586 | + product_data = inv_line.get('product_id', {}) |
587 | + line_account_id = False |
588 | + # for the lines related to a product: use the account of the product / else use the one of the source invoice line |
589 | + if product_data: |
590 | + default_code = product_data.get('default_code', '') |
591 | + product_id = so_po_common_obj.get_product_id(cr, uid, product_data, default_code=default_code, context=context) or False |
592 | + if not product_id: |
593 | + raise osv.except_osv(_('Error'), _("Product %s not found.") % default_code) |
594 | + product = product_obj.browse(cr, uid, product_id, fields_to_fetch=['active', 'default_code', 'product_tmpl_id', 'categ_id'], |
595 | + context=context) |
596 | + if not product.active: |
597 | + raise osv.except_osv(_('Error'), _("The product %s is inactive.") % product.default_code or '') |
598 | + line_account_id = product.product_tmpl_id.property_account_expense and product.product_tmpl_id.property_account_expense.id |
599 | + if not line_account_id: |
600 | + line_account_id = product.categ_id and product.categ_id.property_account_expense_categ and product.categ_id.property_account_expense_categ.id |
601 | + else: |
602 | + account_code = inv_line.get('account_id', {}).get('code', '') |
603 | + if not account_code: |
604 | + raise osv.except_osv(_('Error'), _("Impossible to retrieve the account code at line level.")) |
605 | + account_ids = account_obj.search(cr, uid, [('code', '=', account_code)], limit=1, context=context) |
606 | + if not account_ids: |
607 | + raise osv.except_osv(_('Error'), _("Account code %s not found.") % account_code) |
608 | + line_account_id = account_ids[0] |
609 | + if not line_account_id: |
610 | + raise osv.except_osv(_('Error'), _("Error when retrieving the account at line level.")) |
611 | + line_account = account_obj.browse(cr, uid, line_account_id, |
612 | + fields_to_fetch=['activation_date', 'inactivation_date'], context=context) |
613 | + if inv_posting_date < line_account.activation_date or \ |
614 | + (line_account.inactivation_date and inv_posting_date >= line_account.inactivation_date): |
615 | + raise osv.except_osv(_('Error'), _('The account "%s - %s" is inactive.') % (line_account.code, line_account.name)) |
616 | + uom_id = False |
617 | + uom_data = inv_line.get('uos_id', {}) |
618 | + if uom_data: |
619 | + uom_name = uom_data.get('name', '') |
620 | + uom_ids = product_uom_obj.search(cr, uid, [('name', '=', uom_name)], limit=1, context=context) |
621 | + if not uom_ids: |
622 | + raise osv.except_osv(_('Error'), _("Unit of Measure %s not found.") % uom_name) |
623 | + uom_id = uom_ids[0] |
624 | + quantity = inv_line.get('quantity', 0.0) |
625 | + inv_line_vals = { |
626 | + 'invoice_id': inv_id, |
627 | + 'account_id': line_account_id, |
628 | + 'name': line_name, |
629 | + 'quantity': quantity, |
630 | + 'price_unit': inv_line.get('price_unit', 0.0), |
631 | + 'discount': inv_line.get('discount', 0.0), |
632 | + 'product_id': product_id, |
633 | + 'uos_id': uom_id, |
634 | + } |
635 | + if from_supply and inv_linked_po: |
636 | + # fill in the AD at line level if applicable |
637 | + # search the matching between PO line and invoice line based on description/product/quantity |
638 | + matching_po_line = False |
639 | + for po_line in inv_linked_po.order_line: |
640 | + if po_line.name == line_name and po_line.product_id and po_line.product_id.id == product_id and \ |
641 | + po_line.product_qty == quantity and po_line.state not in ('draft', 'cancel', 'cancel_r'): |
642 | + matching_po_line = po_line |
643 | + break |
644 | + if matching_po_line: |
645 | + po_line_distrib = matching_po_line.analytic_distribution_id |
646 | + self._create_analytic_distrib(cr, uid, inv_line_vals, po_line_distrib, context=context) # update inv_line_vals |
647 | + inv_line_obj.create(cr, uid, inv_line_vals, context=context) |
648 | + |
649 | + def create_invoice_from_sync(self, cr, uid, source, invoice_data, context=None): |
650 | + """ |
651 | + Creates automatic counterpart invoice at synchro time. |
652 | + Intermission workflow: an IVO sent generates an IVI |
653 | + Intersection workflow: an STV sent generates an SI |
654 | + """ |
655 | + self._logger.info("+++ Create an account.invoice in %s matching the one sent by %s" % (cr.dbname, source)) |
656 | + if context is None: |
657 | + context = {} |
658 | + journal_obj = self.pool.get('account.journal') |
659 | + currency_obj = self.pool.get('res.currency') |
660 | + partner_obj = self.pool.get('res.partner') |
661 | + user_obj = self.pool.get('res.users') |
662 | + po_obj = self.pool.get('purchase.order') |
663 | + stock_picking_obj = self.pool.get('stock.picking') |
664 | + invoice_dict = invoice_data.to_dict() |
665 | + # the counterpart instance must exist and be active |
666 | + partner_ids = partner_obj.search(cr, uid, [('name', '=', source), ('active', '=', True)], limit=1, context=context) |
667 | + if not partner_ids: |
668 | + raise osv.except_osv(_('Error'), _("The partner %s doesn't exist or is inactive.") % source) |
669 | + partner_id = partner_ids[0] |
670 | + partner = partner_obj.browse(cr, uid, partner_id, fields_to_fetch=['property_account_payable', 'name'], context=context) |
671 | + journal_type = invoice_dict.get('journal_id', {}).get('type', '') |
672 | + if not journal_type or journal_type not in ('sale', 'intermission'): |
673 | + raise osv.except_osv(_('Error'), _("Impossible to retrieve the journal type, or the journal type is incorrect.")) |
674 | + currency_name = invoice_dict.get('currency_id', {}).get('name', '') |
675 | + if not currency_name: |
676 | + raise osv.except_osv(_('Error'), _("Impossible to retrieve the currency.")) |
677 | + currency_ids = currency_obj.search(cr, uid, [('name', '=', currency_name), ('currency_table_id', '=', False), |
678 | + ('active', '=', True)], limit=1, context=context) |
679 | + if not currency_ids: |
680 | + raise osv.except_osv(_('Error'), _("Currency %s not found or inactive.") % currency_name) |
681 | + currency_id = currency_ids[0] |
682 | + number = invoice_dict.get('number', '') |
683 | + state = invoice_dict.get('state', '') # note that we get the real state as the doc can be beyond the "open" state at sync. time |
684 | + doc_date = invoice_dict.get('document_date', time.strftime('%Y-%m-%d')) |
685 | + posting_date = invoice_dict.get('date_invoice', time.strftime('%Y-%m-%d')) |
686 | + description = invoice_dict.get('name', '') |
687 | + source_doc = invoice_dict.get('origin', '') |
688 | + from_supply = invoice_dict.get('from_supply', False) |
689 | + inv_lines = invoice_dict.get('invoice_line', []) |
690 | + po = False |
691 | + vals = {} |
692 | + # STV in sending instance: generates an SI in the receiving instance |
693 | + if journal_type == 'sale': |
694 | + pur_journal_ids = journal_obj.search(cr, uid, [('type', '=', 'purchase'), ('is_current_instance', '=', True)], limit=1, context=context) |
695 | + if not pur_journal_ids: |
696 | + raise osv.except_osv(_('Error'), _("No Purchase journal found for the current instance.")) |
697 | + # for the SI use the Account Payable of the partner |
698 | + si_account = partner.property_account_payable |
699 | + if not si_account or posting_date < si_account.activation_date or \ |
700 | + (si_account.inactivation_date and posting_date >= si_account.inactivation_date): |
701 | + raise osv.except_osv(_('Error'), _("Account Payable not found or inactive for the partner %s.") % partner.name) |
702 | + vals.update( |
703 | + { |
704 | + 'journal_id': pur_journal_ids[0], |
705 | + 'account_id': si_account.id, |
706 | + 'type': 'in_invoice', |
707 | + 'is_direct_invoice': False, |
708 | + 'is_inkind_donation': False, |
709 | + 'is_debit_note': False, |
710 | + 'is_intermission': False, |
711 | + } |
712 | + ) |
713 | + # IVO in sending instance: generates an IVI in the receiving instance |
714 | + elif journal_type == 'intermission': |
715 | + int_journal_ids = journal_obj.search(cr, uid, [('type', '=', 'intermission'), ('is_current_instance', '=', True)], limit=1, context=context) |
716 | + if not int_journal_ids: |
717 | + raise osv.except_osv(_('Error'), _("No Intermission journal found for the current instance.")) |
718 | + # for the IVI use the Intermission counterpart account from the Company form |
719 | + ivi_account = user_obj.browse(cr, uid, uid, fields_to_fetch=['company_id'], context=context).company_id.intermission_default_counterpart |
720 | + if not ivi_account or posting_date < ivi_account.activation_date or \ |
721 | + (ivi_account.inactivation_date and posting_date >= ivi_account.inactivation_date): |
722 | + raise osv.except_osv(_('Error'), _("The Intermission counterpart account is missing in the Company form or is inactive.")) |
723 | + vals.update( |
724 | + { |
725 | + 'journal_id': int_journal_ids[0], |
726 | + 'account_id': ivi_account.id, |
727 | + 'type': 'in_invoice', |
728 | + 'is_inkind_donation': False, |
729 | + 'is_debit_note': False, |
730 | + 'is_intermission': True, |
731 | + } |
732 | + ) |
733 | + # common fields whatever the invoice type |
734 | + if from_supply: |
735 | + po_id = False |
736 | + po_number = '' |
737 | + fo_number = '' |
738 | + ship_or_out_ref = '' |
739 | + main_in = False |
740 | + # extract PO number, and Shipment or Simple Out ref, from refs looking like: |
741 | + # "se_HQ2C1.19/se_HQ2/HT101/PO00001 : SHIP/00002-01" or "se_HQ1C2.19/se_HQ1/HT201/PO00003 : OUT/00001" |
742 | + inv_name_split = description.split() |
743 | + if inv_name_split: |
744 | + po_number = inv_name_split[0].split('.')[-1] |
745 | + po_ids = po_obj.search(cr, uid, [('name', '=', po_number)], limit=1, context=context) |
746 | + if po_ids: |
747 | + po_id = po_ids[0] |
748 | + ship_or_out_ref = inv_name_split[-1] |
749 | + # extract FO number from source docs looking like: |
750 | + # "SHIP/00001-04:19/se_HQ1/HT101/FO00007" or "OUT/00003:19/se_HQ1/HT101/FO00008" |
751 | + inv_source_doc_split = source_doc.split(':') |
752 | + if inv_source_doc_split: |
753 | + fo_number = inv_source_doc_split[-1] |
754 | + if po_id: |
755 | + po = po_obj.browse(cr, uid, po_id, fields_to_fetch=['picking_ids', 'analytic_distribution_id', 'order_line'], context=context) |
756 | + shipment_ref = "%s.%s" % (source or '', ship_or_out_ref or '') |
757 | + # get the "main" IN |
758 | + main_in_ids = stock_picking_obj.search(cr, uid, |
759 | + [('id', 'in', [picking.id for picking in po.picking_ids]), |
760 | + ('shipment_ref', '=', shipment_ref)], |
761 | + limit=1, context=context) |
762 | + if main_in_ids: |
763 | + main_in = stock_picking_obj.browse(cr, uid, main_in_ids[0], fields_to_fetch=['name'], context=context) |
764 | + # fill in the Analytic Distribution |
765 | + # at header level if applicable |
766 | + po_distrib = po.analytic_distribution_id |
767 | + self._create_analytic_distrib(cr, uid, vals, po_distrib, context=context) # update vals |
768 | + # note: in case a FO would have been manually created the PO and IN would be missing in the ref/source doc, |
769 | + # but the same codification is used so it's visible that sthg is missing |
770 | + description = "%s.%s : %s" % (source, fo_number, main_in and main_in.name or '') # e.g. se_HQ1C1.19/se_HQ1/HT101/FO00008 : IN/00009 |
771 | + source_doc = "%s:%s" % (main_in and main_in.name or '', po_id and po_number or '') # e.g. IN/00009:19/se_HQ1/HT201/PO00009 |
772 | + vals.update( |
773 | + { |
774 | + 'partner_id': partner_id, |
775 | + 'currency_id': currency_id, |
776 | + 'document_date': doc_date, |
777 | + 'date_invoice': posting_date, |
778 | + 'name': description, |
779 | + 'origin': source_doc, |
780 | + 'counterpart_inv_number': number, |
781 | + 'counterpart_inv_status': state, |
782 | + 'from_supply': from_supply, |
783 | + 'synced': True, |
784 | + } |
785 | + ) |
786 | + inv_id = self.create(cr, uid, vals, context=context) |
787 | + if inv_id: |
788 | + self._create_invoice_lines(cr, uid, inv_lines, inv_id, posting_date, po, from_supply, context=context) |
789 | + if journal_type == 'sale': |
790 | + self._logger.info("SI No. %s created successfully." % inv_id) |
791 | + elif journal_type == 'intermission': |
792 | + self._logger.info("IVI No. %s created successfully." % inv_id) |
793 | + |
794 | + def update_counterpart_inv(self, cr, uid, source, invoice_data, state, context=None): |
795 | + """ |
796 | + Updates the Counterpart Invoice Number and Status (to be triggered at synchro time) |
797 | + |
798 | + For the record: |
799 | + In most cases the state "Open" of the Out Invoices will be updated following both msg rules "create_invoice_from_sync" and |
800 | + "update_counterpart_inv_opened". However "update_counterpart_inv_opened" can't be skipped to cover use cases such as: |
801 | + - in C1: open IVO and reconcile the related JI manually: IVO is in Paid state |
802 | + - sync from C1 to C2: the counterpart inv. status in the IVI generated is directly: Paid |
803 | + - in C1: unreconcile IVO JI. The IVO is back to Open. |
804 | + - sync from C1 to C2: the counterpart inv. status in the related IVI is updated to: Open |
805 | + """ |
806 | + self._logger.info("+++ Update Counterpart Invoice data from %s" % source) |
807 | + if context is None: |
808 | + context = {} |
809 | + invoice_dict = invoice_data.to_dict() |
810 | + number = invoice_dict.get('number', '') |
811 | + counterpart_inv_number = invoice_dict.get('counterpart_inv_number', '') |
812 | + if state: |
813 | + vals = { |
814 | + 'counterpart_inv_status': state, |
815 | + } |
816 | + if number: |
817 | + vals.update( |
818 | + { |
819 | + 'counterpart_inv_number': number, |
820 | + } |
821 | + ) |
822 | + inv_ids = [] |
823 | + if counterpart_inv_number: |
824 | + inv_ids = self.search(cr, uid, [('number', '=', counterpart_inv_number)], limit=1, context=context) |
825 | + elif not counterpart_inv_number and number: |
826 | + # use case where the state of the IVO/STV is updated before the related IVI/SI has been opened |
827 | + inv_ids = self.search(cr, uid, [('counterpart_inv_number', '=', number)], limit=1, context=context) |
828 | + if inv_ids: |
829 | + self.write(cr, uid, inv_ids[0], vals, context=context) |
830 | + # note that the "Counterpart Inv. Number" received is the "Number" of the invoice updated! |
831 | + self._logger.info("account.invoice %s: Counterpart Invoice %s set to %s" % (counterpart_inv_number, number, state)) |
832 | + |
833 | + def update_counterpart_inv_opened(self, cr, uid, source, invoice_data, context=None): |
834 | + self.update_counterpart_inv(cr, uid, source, invoice_data, 'open', context=context) |
835 | + |
836 | + def update_counterpart_inv_paid(self, cr, uid, source, invoice_data, context=None): |
837 | + self.update_counterpart_inv(cr, uid, source, invoice_data, 'paid', context=context) |
838 | + |
839 | + def update_counterpart_inv_cancelled(self, cr, uid, source, invoice_data, context=None): |
840 | + self.update_counterpart_inv(cr, uid, source, invoice_data, 'cancel', context=context) |
841 | + |
842 | + |
843 | +account_invoice_sync() |
844 | + |
845 | + |
846 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
847 | |
848 | === modified file 'bin/addons/account_override/account_invoice_view.xml' |
849 | --- bin/addons/account_override/account_invoice_view.xml 2018-02-01 13:22:25 +0000 |
850 | +++ bin/addons/account_override/account_invoice_view.xml 2019-07-15 07:18:58 +0000 |
851 | @@ -43,7 +43,7 @@ |
852 | <field name="line_number"/> |
853 | </xpath> |
854 | <xpath expr="//field[@name='date_invoice']" position="before"> |
855 | - <field name="document_date"/> |
856 | + <field name="document_date" attrs="{'readonly': [('type', '=', 'in_invoice'), ('synced', '=', True)]}"/> |
857 | </xpath> |
858 | <xpath expr="//field[@name='period_id']" position="replace"> |
859 | </xpath> |
860 | @@ -52,7 +52,9 @@ |
861 | <button name='invoice_cancel' position="replace"> |
862 | <!-- The widget boolean permit to the attrs to work efficiently --> |
863 | <field name="purchase_ids" invisible="1" widget="boolean" readonly="1" /> |
864 | - <button name="invoice_cancel" string="Cancel" icon="gtk-cancel" attrs="{'invisible': ['|', ('state', 'in', ['open', 'paid']), ('purchase_ids', '!=', False)]}" confirm="You are about to cancel this invoice. Do you want to proceed?"/> |
865 | + <button name="invoice_cancel" string="Cancel" icon="gtk-cancel" |
866 | + attrs="{'invisible': ['|', '|', ('state', 'in', ['open', 'paid']), ('purchase_ids', '!=', False), ('synced', '=', True)]}" |
867 | + confirm="You are about to cancel this invoice. Do you want to proceed?"/> |
868 | </button> |
869 | <xpath expr="//button[@name='invoice_open']" position="after" > |
870 | <button name="button_split_invoice" states="draft,proforma2" type="object" string="Split Invoice" icon="gtk-cut"/> |
871 | @@ -482,13 +484,22 @@ |
872 | <field name="type" invisible="1"/> |
873 | <field name="is_intermission" invisible="1"/> |
874 | <!-- US-370: use the change currency button --> |
875 | - <field name="currency_id" width="50"/> |
876 | - <button name="%(account.action_account_change_currency)d" type="action" icon="terp-stock_effects-object-colorize" string="Change" attrs="{'invisible':[('state','!=','draft')]}" /> |
877 | + <field name="currency_id" width="50" attrs="{'readonly': [('type', '=', 'in_invoice'), ('synced', '=', True)]}"/> |
878 | + <button name="%(account.action_account_change_currency)d" type="action" |
879 | + icon="terp-stock_effects-object-colorize" string="Change" |
880 | + attrs="{'invisible': [('state', '!=', 'draft')], |
881 | + 'readonly': [('type', '=', 'in_invoice'), ('synced', '=', True)]}" /> |
882 | <newline/> |
883 | - <field string="Partner" name="partner_id" on_change="onchange_partner_id(type,partner_id,date_invoice,payment_term, partner_bank_id,company_id, False, is_intermission, False, False, account_id)" domain="[('by_invoice_type', '=', True), ('partner_type', '=', 'intermission')]" context="{'type': context.get('type')}"/> |
884 | + <field string="Partner" name="partner_id" |
885 | + on_change="onchange_partner_id(type,partner_id, date_invoice,payment_term, partner_bank_id, company_id, False, is_intermission, False, False, account_id)" |
886 | + domain="[('by_invoice_type', '=', True), ('partner_type', '=', 'intermission')]" |
887 | + context="{'type': context.get('type')}" |
888 | + attrs="{'readonly': ['|', |
889 | + '&', ('type', '=', 'in_invoice'), ('synced', '=', True), |
890 | + '&', ('type', '=', 'out_invoice'), ('from_supply', '=', True)]}"/> |
891 | <field domain="[('partner_id','=',partner_id)]" name="address_invoice_id" string="Partner address"/> |
892 | <newline/> |
893 | - <field name="document_date" string="I/MI voucher date"/> |
894 | + <field name="document_date" string="I/MI voucher date" attrs="{'readonly': [('type', '=', 'in_invoice'), ('synced', '=', True)]}"/> |
895 | <field name="date_invoice"/> |
896 | <newline/> |
897 | <group colspan="8" col="8" attrs="{'invisible': [('analytic_distribution_id', '=', False)]}"> |
898 | @@ -505,13 +516,19 @@ |
899 | <notebook colspan="4"> |
900 | <page string="Invoice"> |
901 | <field name="account_id" domain="[('company_id', '=', company_id), ('restricted_area', '=', 'intermission_header')]"/> |
902 | - <field name="name" string="Reference"/> |
903 | + <field name="name" string="Reference" attrs="{'readonly': [('from_supply', '=', True)]}"/> |
904 | <newline/> |
905 | <group name="import" string=" Import Lines " colspan="4" col="4" attrs="{'invisible':[('state', '!=', 'draft')]}"> |
906 | - <button name="wizard_import_si_line" string="Import lines" icon="gtk-dnd" type="object" attrs="{'invisible':[('state', '!=', 'draft')]}"/> |
907 | + <button name="wizard_import_si_line" string="Import lines" icon="gtk-dnd" type="object" |
908 | + attrs="{'invisible': [('state', '!=', 'draft')], |
909 | + 'readonly': ['|', |
910 | + ('from_supply', '=', True), |
911 | + '&', ('type', '=', 'in_invoice'), ('synced', '=', True)]}"/> |
912 | </group> |
913 | - <field colspan="4" name="invoice_line" nolabel="1" widget="one2many_list" context="{'is_intermission': True}"> |
914 | - <tree string="Intermission Voucher Lines"> |
915 | + <field colspan="4" name="invoice_line" nolabel="1" widget="one2many_list" context="{'is_intermission': True, 'from_inv_form': True}"> |
916 | + <tree string="Intermission Voucher Lines" |
917 | + colors="red:analytic_distribution_state == 'invalid' or inactive_product == True;black:inactive_product == False and analytic_distribution_state in ('none', 'valid')"> |
918 | + <field name="line_number"/> |
919 | <field name="is_corrected" invisible="1"/> |
920 | <button name="button_open_analytic_lines" string="Have been corrected" type="object" icon="terp-mail-" attrs="{'invisible': [('is_corrected', '=', False)]}"/> |
921 | <field name="name"/> |
922 | @@ -523,7 +540,7 @@ |
923 | <field name="analytic_distribution_state" invisible="1"/> |
924 | <field name="have_analytic_distribution_from_header" invisible="1"/> |
925 | <field name="quantity"/> |
926 | - <field name="uos_id" string="UOM" invisible="1" /> |
927 | + <field name="uos_id" string="UOM"/> |
928 | <field name="price_unit"/> |
929 | <field name="price_subtotal"/> |
930 | <field name="inactive_product" invisible="1" /> |
931 | @@ -532,12 +549,42 @@ |
932 | <form string="Intermission Voucher Lines"> |
933 | <notebook> |
934 | <page string="Line"> |
935 | - <field name="name" default_focus="1"/> |
936 | + <field name="from_supply" invisible="1"/> |
937 | + <field name="synced" invisible="1"/> |
938 | + <field name="invoice_type" invisible="1"/> |
939 | + <field name="product_id" |
940 | + on_change="product_id_change(product_id, uos_id, quantity, name, parent.type, parent.partner_id, parent.fiscal_position, price_unit, parent.address_invoice_id, parent.currency_id, {'company_id': parent.company_id})" |
941 | + default_focus="1" |
942 | + attrs="{'readonly': ['|', |
943 | + ('from_supply', '=', True), |
944 | + '&', ('invoice_type', '=', 'in_invoice'), ('synced', '=', True)]}" /> |
945 | + <field name="uos_id" |
946 | + on_change="uos_id_change(product_id, uos_id, quantity, name, parent.type, parent.partner_id, parent.fiscal_position, price_unit, parent.address_invoice_id, parent.currency_id, {'company_id': parent.company_id})" |
947 | + attrs="{'readonly': ['|', |
948 | + ('from_supply', '=', True), |
949 | + '&', ('invoice_type', '=', 'in_invoice'), ('synced', '=', True)]}" |
950 | + /> |
951 | + <field name="quantity" attrs="{'readonly': ['|', |
952 | + ('from_supply', '=', True), |
953 | + '&', ('invoice_type', '=', 'in_invoice'), ('synced', '=', True)]}"/> |
954 | + <field name="price_unit" attrs="{'readonly': [('invoice_type', '=', 'in_invoice'), ('synced', '=', True)]}"/> |
955 | + <field name="discount" groups="base.group_extended" attrs="{'readonly': [('invoice_type', '=', 'in_invoice'), ('synced', '=', True)]}"/> |
956 | + <field name="name" colspan="4"/> |
957 | <field name="account_id" domain="[('restricted_area', '=', 'intermission_lines')]"/> |
958 | - <field name="quantity"/> |
959 | - <field name="uos_id" string="UOM" invisible="1"/> |
960 | - <field name="price_unit"/> |
961 | - <field name="price_subtotal"/> |
962 | + <group colspan="6"> |
963 | + <field name="analytic_distribution_state" invisible="1"/> |
964 | + <field name="newline" invisible="1" /> |
965 | + <field name="is_allocatable" invisible="1"/> |
966 | + <group colspan="2" col="4"> |
967 | + <button name="button_analytic_distribution" string="Change analytic distribution" |
968 | + type="object" icon="terp-check" context="context" colspan="1" |
969 | + attrs="{'invisible': ['|','|', ('newline', '=', True), ('analytic_distribution_state', '!=', 'valid'), ('is_allocatable', '=', False)]}" /> |
970 | + <button name="button_analytic_distribution" string="Change analytic distribution" |
971 | + type="object" icon="terp-emblem-important" context="context" colspan="1" |
972 | + attrs="{'invisible': ['|','|', ('newline', '=', True), ('analytic_distribution_state', '=', 'valid'), ('is_allocatable', '=', False)]}" /> |
973 | + <field name="analytic_distribution_state_recap" attrs="{'invisible': [('is_allocatable', '=', False)]}"/> |
974 | + </group> |
975 | + </group> |
976 | </page> |
977 | <page string="Notes"> |
978 | <field name="note" nolabel="1" colspan="4"/> |
979 | @@ -550,12 +597,26 @@ |
980 | <field name="state"/> |
981 | <field name="amount_total"/> |
982 | </group> |
983 | - <group col="2" colspan="4" states="draft"> |
984 | + <group col="6" colspan="4" states="draft"> |
985 | <label string=""/> |
986 | - <button name="invoice_open" type="object" states="draft" string="Validate" icon="gtk-go-forward"/> |
987 | + <!-- add a confirmation step only for IVOs when "synced" isn't selected --> |
988 | + <button name="invoice_open" type="object" string="Validate" |
989 | + icon="gtk-go-forward" |
990 | + attrs="{'invisible': ['|', |
991 | + ('state', '!=', 'draft'), |
992 | + '&', ('type', '=', 'out_invoice'), ('synced', '=', False)]}"/> |
993 | + <button name="invoice_open_with_confirmation" type="object" string="Validate" |
994 | + icon="gtk-go-forward" |
995 | + confirm="Are you sure you want to validate this invoice without synchronization?" |
996 | + attrs="{'invisible': ['|', '|', |
997 | + ('state', '!=', 'draft'), |
998 | + ('type', '!=', 'out_invoice'), |
999 | + ('synced', '=', True)]}"/> |
1000 | </group> |
1001 | - <group col="2" colspan="4" states="open,paid"> |
1002 | + <group col="6" colspan="4" states="open,paid"> |
1003 | <label string=""/> |
1004 | + <button name="%(account.action_account_invoice_refund)d" type="action" string="Refund" icon="gtk-execute" |
1005 | + attrs="{'invisible': [('state', '!=', 'open')]}"/> |
1006 | <button name="%(account.account_invoices)d" string="Print Intermission Voucher" type="action" icon="gtk-print" states="open,paid"/> |
1007 | </group> |
1008 | </page> |
1009 | @@ -563,15 +624,29 @@ |
1010 | <field name="company_id" on_change="onchange_company_id(company_id,partner_id,type,invoice_line,currency_id)" widget="selection" groups="base.group_multi_company"/> |
1011 | <newline/> |
1012 | <field name="date_due"/> |
1013 | - <field name="user_id"/> |
1014 | + <field name="user_id" |
1015 | + attrs="{'readonly': ['|', |
1016 | + '&', ('type', '=', 'in_invoice'), ('synced', '=', True), |
1017 | + '&', ('type', '=', 'out_invoice'), ('from_supply', '=', True)]}"/> |
1018 | <newline/> |
1019 | <field domain="[('partner_id.ref_companies', 'in', [company_id])]" name="partner_bank_id" /> |
1020 | - <field name="origin"/> |
1021 | + <field name="origin" attrs="{'readonly': [('from_supply', '=', True)]}"/> |
1022 | <field colspan="4" domain="[('partner_id','=',partner_id)]" name="address_contact_id" /> |
1023 | <field name="move_id" /> |
1024 | <separator colspan="4" string="Additional Information"/> |
1025 | <field colspan="4" name="comment" nolabel="1"/> |
1026 | </page> |
1027 | + <page string="Counterpart Invoice"> |
1028 | + <field name="from_supply" invisible="1"/> |
1029 | + <field name="synced" |
1030 | + attrs="{'readonly': ['|', '|', |
1031 | + ('from_supply', '=', True), |
1032 | + ('state', '!=', 'draft'), |
1033 | + ('type', '=', 'in_invoice')]}"/> <!-- IVI can never be ticked as "Synced" manually --> |
1034 | + <newline/> |
1035 | + <field name="counterpart_inv_number"/> |
1036 | + <field name="counterpart_inv_status"/> |
1037 | + </page> |
1038 | </notebook> |
1039 | </form> |
1040 | </field> |
1041 | @@ -610,7 +685,11 @@ |
1042 | <button name="invoice_proforma2" position="replace"/> |
1043 | <xpath expr="/form/notebook/page[@string='Invoice']/field[@name='invoice_line']" position="before" > |
1044 | <group name="import" string=" Import Lines " colspan="4" col="4" attrs="{'invisible':[('state', '!=', 'draft')]}"> |
1045 | - <button name="wizard_import_si_line" string="Import lines" icon="gtk-dnd" type="object" attrs="{'invisible':[('state', '!=', 'draft')]}"/> |
1046 | + <button name="wizard_import_si_line" string="Import lines" icon="gtk-dnd" type="object" |
1047 | + attrs="{'invisible': [('state', '!=', 'draft')], |
1048 | + 'readonly': [('type', '=', 'out_invoice'), |
1049 | + ('from_supply', '=', True), |
1050 | + ('partner_type', 'in', ('intermission', 'section'))]}"/> |
1051 | </group> |
1052 | </xpath> |
1053 | <xpath expr="/form/notebook/page[@string='Invoice']/group[3]" position="replace"> |
1054 | @@ -623,11 +702,27 @@ |
1055 | <field name="residual"/> |
1056 | <field name="is_debit_note" invisible="1"/> |
1057 | </group> |
1058 | + <field name="partner_type" invisible="1"/> |
1059 | <group col="8" colspan="4"> |
1060 | <button name="invoice_cancel" states="proforma2,open" string="Cancel" icon="gtk-cancel"/> |
1061 | <button name="%(account.action_account_invoice_refund)d" type='action' string='Refund' icon="gtk-execute" attrs="{'invisible': ['|', ('state', 'in', ['draft']), ('type', 'in', ['in_refund', 'out_refund'])]}"/> |
1062 | <button name='%(account.action_account_state_open)d' type='action' string='Re-Open' states='paid' icon="gtk-convert" groups="base.group_no_one"/> |
1063 | - <button name="invoice_open" states="draft,proforma2" string="Validate" icon="gtk-go-forward" type="object"/> |
1064 | + <!-- add a confirmation step only for STV (not for Customer Refunds) |
1065 | + when the partner type is compatible with a synchro but "synced" isn't ticked --> |
1066 | + <button name="invoice_open" type="object" string="Validate" |
1067 | + icon="gtk-go-forward" |
1068 | + attrs="{'invisible': ['|', |
1069 | + ('state', '!=', 'draft'), |
1070 | + '&', '&', |
1071 | + ('type', '=', 'out_invoice'), ('synced', '=', False), ('partner_type', 'in', ('intermission', 'section')) ]}"/> |
1072 | + <button name="invoice_open_with_confirmation" type="object" string="Validate" |
1073 | + icon="gtk-go-forward" |
1074 | + confirm="Are you sure you want to validate this invoice without synchronization?" |
1075 | + attrs="{'invisible': ['|', '|', '|', |
1076 | + ('state', '!=', 'draft'), |
1077 | + ('type', '!=', 'out_invoice'), |
1078 | + ('synced', '=', True), |
1079 | + ('partner_type', 'not in', ('intermission', 'section'))]}"/> |
1080 | <button name="%(account.account_invoices)d" string="Print Invoice" type="action" icon="gtk-print" states="open,paid,proforma,sale,proforma2"/> |
1081 | </group> |
1082 | </xpath> |
1083 | @@ -813,7 +908,7 @@ |
1084 | <field eval="False" name="view_id"/> |
1085 | <!-- US-2704 if the domain change, do not forget to update the domain of account_board_supplier_invoice_draft in finance/board_account_view.xml --> |
1086 | <field name="domain">[('type','=','in_invoice'), ('is_direct_invoice', '=', False), ('is_inkind_donation', '=', False), ('is_debit_note', "=", False), ('is_intermission', '=', False)]</field> |
1087 | - <field name="context">{'type':'in_invoice', 'journal_type': 'purchase'}</field> |
1088 | + <field name="context">{'type': 'in_invoice', 'journal_type': 'purchase', 'from_inv_form': True}</field> |
1089 | <field name="search_view_id" ref="account.view_account_invoice_filter"/> |
1090 | <field name="help">With Supplier Invoices you can enter and manage invoices issued by your suppliers. |
1091 | OpenERP can also generate draft invoices automatically from purchase orders or receipts. This way, you can control the invoice |
1092 | |
1093 | === modified file 'bin/addons/account_override/invoice.py' |
1094 | --- bin/addons/account_override/invoice.py 2019-05-21 08:19:49 +0000 |
1095 | +++ bin/addons/account_override/invoice.py 2019-07-15 07:18:58 +0000 |
1096 | @@ -28,12 +28,14 @@ |
1097 | from tools.translate import _ |
1098 | from lxml import etree |
1099 | from datetime import datetime |
1100 | +from msf_partner import PARTNER_TYPE |
1101 | import re |
1102 | import netsvc |
1103 | |
1104 | |
1105 | import decimal_precision as dp |
1106 | |
1107 | + |
1108 | class account_invoice(osv.osv): |
1109 | _name = 'account.invoice' |
1110 | _inherit = 'account.invoice' |
1111 | @@ -251,6 +253,8 @@ |
1112 | 'st_lines': fields.one2many('account.bank.statement.line', 'invoice_id', string="Register lines", readonly=True, help="Register lines that have a link to this invoice."), |
1113 | 'can_merge_lines': fields.function(_get_can_merge_lines, method=True, type='boolean', string='Can merge lines ?'), |
1114 | 'is_merged_by_account': fields.boolean("Is merged by account"), |
1115 | + 'partner_type': fields.related('partner_id', 'partner_type', string='Partner Type', type='selection', |
1116 | + selection=PARTNER_TYPE, readonly=True, store=False), |
1117 | } |
1118 | |
1119 | _defaults = { |
1120 | @@ -814,6 +818,35 @@ |
1121 | 'view_id': supplier_view_id} |
1122 | return super(account_invoice, self).log(cr, uid, inv_id, message, secondary, action_xmlid, local_ctx) |
1123 | |
1124 | + def _check_tax_allowed(self, cr, uid, ids, context=None): |
1125 | + """ |
1126 | + Raises an error if a tax is used with an Intermission or Intersection partner |
1127 | + """ |
1128 | + if context is None: |
1129 | + context = {} |
1130 | + if isinstance(ids, (int, long)): |
1131 | + ids = [ids] |
1132 | + warning_msg = _('Taxes are forbidden with Intermission and Intersection partners.') |
1133 | + for inv in self.browse(cr, uid, ids, fields_to_fetch=['partner_id', 'tax_line', 'invoice_line'], context=context): |
1134 | + if inv.partner_id.partner_type in ('intermission', 'section'): |
1135 | + if inv.tax_line: |
1136 | + raise osv.except_osv(_('Warning'), warning_msg) |
1137 | + for inv_line in inv.invoice_line: |
1138 | + if inv_line.invoice_line_tax_id: |
1139 | + raise osv.except_osv(_('Warning'), warning_msg) |
1140 | + |
1141 | + def _check_sync_allowed(self, cr, uid, ids, context=None): |
1142 | + """ |
1143 | + Raises an error if the doc is marked as Synced whereas the Partner is neither Intermission nor Intersection |
1144 | + """ |
1145 | + if context is None: |
1146 | + context = {} |
1147 | + if isinstance(ids, (int, long)): |
1148 | + ids = [ids] |
1149 | + for inv in self.browse(cr, uid, ids, fields_to_fetch=['partner_id', 'synced'], context=context): |
1150 | + if inv.partner_id.partner_type not in ('intermission', 'section') and inv.synced: |
1151 | + raise osv.except_osv(_('Warning'), _('Synchronized invoices are allowed only with Intermission and Intersection partners.')) |
1152 | + |
1153 | def invoice_open(self, cr, uid, ids, context=None): |
1154 | """ |
1155 | No longer fills the date automatically, but requires it to be set |
1156 | @@ -823,6 +856,8 @@ |
1157 | context = {} |
1158 | self._check_invoice_merged_lines(cr, uid, ids, context=context) |
1159 | self.check_accounts_for_partner(cr, uid, ids, context=context) |
1160 | + self._check_tax_allowed(cr, uid, ids, context=context) |
1161 | + self._check_sync_allowed(cr, uid, ids, context=context) |
1162 | |
1163 | # Prepare workflow object |
1164 | wf_service = netsvc.LocalService("workflow") |
1165 | @@ -871,6 +906,12 @@ |
1166 | |
1167 | return True |
1168 | |
1169 | + def invoice_open_with_confirmation(self, cr, uid, ids, context=None): |
1170 | + """ |
1171 | + Simply calls "invoice_open" (asking for confirmation is done at form level) |
1172 | + """ |
1173 | + return self.invoice_open(cr, uid, ids, context=context) |
1174 | + |
1175 | def action_reconcile_imported_invoice(self, cr, uid, ids, context=None): |
1176 | """ |
1177 | Reconcile each imported invoice with its attached invoice line |
1178 | @@ -1107,6 +1148,21 @@ |
1179 | self._check_header_account(cr, uid, inv_id, inv_type=inv_type, context=context) |
1180 | self._check_line_accounts(cr, uid, inv_id, inv_type=inv_type, context=context) |
1181 | |
1182 | + def update_counterpart_inv_status(self, cr, uid, ids, context=None): |
1183 | + """ |
1184 | + In case an IVO or STV, with an Intermission or Intersection partner and set as Synchronized, is being opened: |
1185 | + set the Counterpart Invoice Status to Draft automatically |
1186 | + """ |
1187 | + if context is None: |
1188 | + context = {} |
1189 | + if isinstance(ids, (int, long)): |
1190 | + ids = [ids] |
1191 | + inv_fields = ['type', 'is_debit_note', 'synced', 'partner_type', 'counterpart_inv_status'] |
1192 | + for inv in self.browse(cr, uid, ids, fields_to_fetch=inv_fields, context=context): |
1193 | + is_ivo_or_stv = inv.type == 'out_invoice' and not inv.is_debit_note |
1194 | + if is_ivo_or_stv and inv.synced and inv.partner_type in ('intermission', 'section') and not inv.counterpart_inv_status: |
1195 | + self.write(cr, uid, inv.id, {'counterpart_inv_status': 'draft'}, context=context) |
1196 | + |
1197 | def action_open_invoice(self, cr, uid, ids, context=None, *args): |
1198 | """ |
1199 | Give function to use when changing invoice to open state |
1200 | @@ -1124,6 +1180,7 @@ |
1201 | if not self.action_reconcile_imported_invoice(cr, uid, ids, context): |
1202 | return False |
1203 | self.check_domain_restrictions(cr, uid, ids, context) # raises an error if one unauthorized element is used |
1204 | + self.update_counterpart_inv_status(cr, uid, ids, context=context) |
1205 | return True |
1206 | |
1207 | |
1208 | @@ -1629,6 +1686,13 @@ |
1209 | relation="account.analytic.account", string='Funding Pool', |
1210 | states={'draft': [('readonly', False)]}, |
1211 | help="Field used for import only"), |
1212 | + 'from_supply': fields.related('invoice_id', 'from_supply', type='boolean', string='From Supply', readonly=True, store=False), |
1213 | + 'synced': fields.related('invoice_id', 'synced', type='boolean', string='Synchronized', readonly=True, store=False), |
1214 | + 'invoice_type': fields.related('invoice_id', 'type', string='Invoice Type', type='selection', readonly=True, store=False, |
1215 | + selection=[('out_invoice', 'Customer Invoice'), |
1216 | + ('in_invoice', 'Supplier Invoice'), |
1217 | + ('out_refund', 'Customer Refund'), |
1218 | + ('in_refund', 'Supplier Refund')]), |
1219 | } |
1220 | |
1221 | _defaults = { |
1222 | @@ -1661,6 +1725,23 @@ |
1223 | if abs(qty) >= too_big_amount or abs(pu) >= too_big_amount or abs(discount) >= too_big_amount or abs(subtotal) >= too_big_amount: |
1224 | raise osv.except_osv(_('Error'), _('Line "%s": one of the numbers entered is more than 10 digits.') % inv_line.name) |
1225 | |
1226 | + def _check_automated_invoice(self, cr, uid, invoice_id, context=None): |
1227 | + """ |
1228 | + Prevents the creation of manual inv. lines if the related invoice has been generated via Sync. or |
1229 | + by a Supply workflow (for Intermission/Intersection partners) |
1230 | + """ |
1231 | + if context is None: |
1232 | + context = {} |
1233 | + inv_obj = self.pool.get('account.invoice') |
1234 | + if invoice_id: |
1235 | + inv_fields = ['from_supply', 'synced', 'type', 'is_inkind_donation', 'partner_type'] |
1236 | + inv = inv_obj.browse(cr, uid, invoice_id, fields_to_fetch=inv_fields, context=context) |
1237 | + ivi_or_si_synced = inv.type == 'in_invoice' and not inv.is_inkind_donation and inv.synced |
1238 | + intermission_or_section_from_supply = inv.partner_type in ('intermission', 'section') and inv.from_supply |
1239 | + if context.get('from_inv_form') and (ivi_or_si_synced or intermission_or_section_from_supply): |
1240 | + raise osv.except_osv(_('Error'), _('This document has been generated via a Supply workflow or via synchronization. ' |
1241 | + 'You can\'t add lines manually.')) |
1242 | + |
1243 | def create(self, cr, uid, vals, context=None): |
1244 | """ |
1245 | Give a line_number to invoice line. |
1246 | @@ -1671,6 +1752,7 @@ |
1247 | """ |
1248 | if not context: |
1249 | context = {} |
1250 | + self._check_automated_invoice(cr, uid, vals.get('invoice_id'), context=context) |
1251 | # Create new number with invoice sequence |
1252 | if vals.get('invoice_id') and self._name in ['account.invoice.line']: |
1253 | invoice = self.pool.get('account.invoice').browse(cr, uid, vals['invoice_id']) |
1254 | @@ -1766,9 +1848,10 @@ |
1255 | |
1256 | def unlink(self, cr, uid, ids, context=None): |
1257 | """ |
1258 | - If invoice is a Direct Invoice and is in draft state: |
1259 | - - compute total amount (check_total field) |
1260 | - - write total to the register line |
1261 | + - If invoice is a Direct Invoice and is in draft state: |
1262 | + - compute total amount (check_total field) |
1263 | + - write total to the register line |
1264 | + - Raise error msg if the related inv. has been generated via Sync. or by a Supply workflow (for Intermission/Intersection partners) |
1265 | """ |
1266 | if not context: |
1267 | context = {} |
1268 | @@ -1776,16 +1859,25 @@ |
1269 | ids = [ids] |
1270 | # Fetch all invoice_id to check |
1271 | direct_invoice_ids = [] |
1272 | + invoice_ids = [] |
1273 | abst_obj = self.pool.get('account.bank.statement.line') |
1274 | for invl in self.browse(cr, uid, ids): |
1275 | - if invl.invoice_id and invl.invoice_id.is_direct_invoice and invl.invoice_id.state == 'draft': |
1276 | - direct_invoice_ids.append(invl.invoice_id.id) |
1277 | - # find account_bank_statement_lines and used this to delete the account_moves and associated records |
1278 | - absl_ids = abst_obj.search(cr, uid, |
1279 | - [('invoice_id','=',invl.invoice_id.id)], |
1280 | - order='NO_ORDER') |
1281 | - if absl_ids: |
1282 | - abst_obj.unlink_moves(cr, uid, absl_ids, context) |
1283 | + if invl.invoice_id and invl.invoice_id.id not in invoice_ids: |
1284 | + invoice = invl.invoice_id |
1285 | + invoice_ids.append(invoice.id) # check each invoice only once |
1286 | + is_ivi_or_si = invoice.type == 'in_invoice' and not invoice.is_inkind_donation |
1287 | + if (is_ivi_or_si and invoice.synced) or (invoice.from_supply and invoice.partner_type in ('intermission', 'section')): |
1288 | + # will be displayed when trying to delete lines manually / merge lines / or split invoices |
1289 | + raise osv.except_osv(_('Error'), _("This document has been generated via a Supply workflow or via synchronization. " |
1290 | + "Existing lines can't be deleted.")) |
1291 | + if invoice.is_direct_invoice and invoice.state == 'draft': |
1292 | + direct_invoice_ids.append(invoice.id) |
1293 | + # find account_bank_statement_lines and use this to delete the account_moves and associated records |
1294 | + absl_ids = abst_obj.search(cr, uid, |
1295 | + [('invoice_id', '=', invoice.id)], |
1296 | + order='NO_ORDER') |
1297 | + if absl_ids: |
1298 | + abst_obj.unlink_moves(cr, uid, absl_ids, context) |
1299 | # Normal behaviour |
1300 | res = super(account_invoice_line, self).unlink(cr, uid, ids, context) |
1301 | # See all direct invoice |
1302 | |
1303 | === modified file 'bin/addons/analytic_distribution/account_invoice_refund.py' |
1304 | --- bin/addons/analytic_distribution/account_invoice_refund.py 2018-05-14 12:41:04 +0000 |
1305 | +++ bin/addons/analytic_distribution/account_invoice_refund.py 2019-07-15 07:18:58 +0000 |
1306 | @@ -43,8 +43,10 @@ |
1307 | # in case of a DI refund from a register line use the dir_invoice_id in context |
1308 | doc_to_refund_id = context.get('dir_invoice_id', False) or (context.get('active_ids') and context['active_ids'][0]) |
1309 | if doc_to_refund_id: |
1310 | - source_type = obj_inv.read(cr, uid, doc_to_refund_id, ['type'], context=context)['type'] |
1311 | - if source_type in ('in_invoice', 'in_refund'): |
1312 | + source = obj_inv.read(cr, uid, doc_to_refund_id, ['type', 'is_intermission'], context=context) |
1313 | + if source['is_intermission']: |
1314 | + args = [('type', '=', 'intermission')] |
1315 | + elif source['type'] in ('in_invoice', 'in_refund'): |
1316 | args = [('type', '=', 'purchase_refund')] |
1317 | if user.company_id.instance_id: |
1318 | args.append(('is_current_instance','=',True)) |
1319 | @@ -72,7 +74,7 @@ |
1320 | jtype = isinstance(context['journal_type'], list) and context['journal_type'][0] or context['journal_type'] |
1321 | if jtype in ('sale', 'sale_refund'): |
1322 | jtype = 'sale_refund' |
1323 | - else: |
1324 | + elif jtype != 'intermission': # for IVO/IVI keep using the Interm. journal |
1325 | jtype = 'purchase_refund' |
1326 | user = self.pool.get('res.users').browse(cr, uid, uid, context=context) |
1327 | for field in res['fields']: |
1328 | @@ -86,13 +88,32 @@ |
1329 | _columns = { |
1330 | 'date': fields.date('Posting date'), |
1331 | 'document_date': fields.date('Document Date', required=True), |
1332 | + 'is_intermission': fields.boolean("Wizard opened from an Intermission Voucher", readonly=True) |
1333 | } |
1334 | |
1335 | + def _get_refund(self, cr, uid, context=None): |
1336 | + """ |
1337 | + Returns the default value for the 'filter_refund' field depending on the context |
1338 | + """ |
1339 | + if context is None: |
1340 | + context = {} |
1341 | + if context.get('is_intermission', False): |
1342 | + return 'modify' |
1343 | + return 'refund' # note that only the "Refund" option is available in DI |
1344 | + |
1345 | + def _get_is_intermission(self, cr, uid, context=None): |
1346 | + """ |
1347 | + Returns True if the wizard has been opened from an Intermission Voucher |
1348 | + """ |
1349 | + if context is None: |
1350 | + context = {} |
1351 | + return context.get('is_intermission', False) |
1352 | + |
1353 | _defaults = { |
1354 | 'document_date': _get_document_date, |
1355 | - #UTP-961: refund DI: only refund option is available |
1356 | - 'filter_refund': 'refund', |
1357 | + 'filter_refund': _get_refund, |
1358 | 'journal_id': _get_journal, # US-193 |
1359 | + 'is_intermission': _get_is_intermission, |
1360 | } |
1361 | |
1362 | def _hook_fields_for_modify_refund(self, cr, uid, *args): |
1363 | |
1364 | === modified file 'bin/addons/analytic_distribution/account_invoice_view.xml' |
1365 | --- bin/addons/analytic_distribution/account_invoice_view.xml 2018-02-23 14:35:29 +0000 |
1366 | +++ bin/addons/analytic_distribution/account_invoice_view.xml 2019-07-15 07:18:58 +0000 |
1367 | @@ -120,10 +120,16 @@ |
1368 | <xpath expr="//separator[@string='Taxes']" position="replace" /> |
1369 | <xpath expr="//field[@name='invoice_line_tax_id']" position="replace"> |
1370 | <field name="vat_ok" invisible="1" /> |
1371 | + <field name="synced" invisible="1" /> |
1372 | <group colspan="4" col="4" attrs="{'invisible': [('vat_ok', '=', False)]}"> |
1373 | <separator colspan="4" string="Taxes"/> |
1374 | - <field colspan="4" name="invoice_line_tax_id" context="{'type':parent.type}" domain="[('parent_id','=',False),('company_id', '=', parent.company_id)]" |
1375 | - nolabel="1"/> |
1376 | + <field colspan="4" |
1377 | + name="invoice_line_tax_id" |
1378 | + context="{'type': parent.type}" |
1379 | + domain="[('parent_id', '=', False), ('company_id', '=', parent.company_id)]" |
1380 | + nolabel="1" |
1381 | + attrs="{'readonly': [('invoice_type', '=', 'in_invoice'), ('synced', '=', True)]}" |
1382 | + /> |
1383 | </group> |
1384 | </xpath> |
1385 | </data> |
1386 | |
1387 | === modified file 'bin/addons/msf_audittrail/audittrail_invoice_data.yml' |
1388 | --- bin/addons/msf_audittrail/audittrail_invoice_data.yml 2019-05-13 09:18:37 +0000 |
1389 | +++ bin/addons/msf_audittrail/audittrail_invoice_data.yml 2019-07-15 07:18:58 +0000 |
1390 | @@ -9,7 +9,8 @@ |
1391 | # Create the rule |
1392 | fields = ['date_invoice', 'state', 'account_id', 'address_invoice_id', 'amount_to_pay', 'analytic_distribution_id', |
1393 | 'check_total', 'comment', 'currency_id', 'fiscal_position', 'name', 'origin', 'partner_id', |
1394 | - 'payment_ids', 'period_id', 'reference', 'reference_type', 'tax_line'] |
1395 | + 'payment_ids', 'period_id', 'reference', 'reference_type', 'tax_line', 'synced', 'counterpart_inv_number', |
1396 | + 'counterpart_inv_status'] |
1397 | |
1398 | fields_ids = self.pool.get('ir.model.fields').search(cr, uid, [('model', '=' ,'account.invoice'), ('name', 'in', fields)], context=context) |
1399 | |
1400 | |
1401 | === modified file 'bin/addons/msf_outgoing/msf_outgoing.py' |
1402 | --- bin/addons/msf_outgoing/msf_outgoing.py 2019-05-10 13:59:15 +0000 |
1403 | +++ bin/addons/msf_outgoing/msf_outgoing.py 2019-07-15 07:18:58 +0000 |
1404 | @@ -1579,6 +1579,7 @@ |
1405 | 'fiscal_position': partner.property_account_position.id, |
1406 | 'date_invoice': context.get('date_inv', False) or today, |
1407 | 'user_id': uid, |
1408 | + 'from_supply': True, |
1409 | } |
1410 | |
1411 | cur_id = shipment.pack_family_memory_ids[0].currency_id.id |
1412 | @@ -1614,6 +1615,7 @@ |
1413 | continue |
1414 | |
1415 | if is_ivo or is_stv: |
1416 | + invoice_vals.update({'synced': True, }) # add "synced" tag for STV and IVO created from Supply flow |
1417 | origin_inv = 'origin' in invoice_vals and invoice_vals['origin'] or False |
1418 | fo = move and move.sale_line_id and move.sale_line_id.order_id or False |
1419 | new_origin = origin_inv and fo and "%s:%s" % (origin_inv, fo.name) |
1420 | |
1421 | === modified file 'bin/addons/msf_profile/data/patches.xml' |
1422 | --- bin/addons/msf_profile/data/patches.xml 2019-06-20 14:28:17 +0000 |
1423 | +++ bin/addons/msf_profile/data/patches.xml 2019-07-15 07:18:58 +0000 |
1424 | @@ -429,5 +429,10 @@ |
1425 | <field name="method">us_6111_nr_field_closed_mar_2018</field> |
1426 | </record> |
1427 | |
1428 | + <!-- UF14.0 --> |
1429 | + <record id="us_6076_set_inv_as_from_supply" model="patch.scripts"> |
1430 | + <field name="method">us_6076_set_inv_as_from_supply</field> |
1431 | + </record> |
1432 | + |
1433 | </data> |
1434 | </openerp> |
1435 | |
1436 | === modified file 'bin/addons/msf_profile/i18n/fr_MF.po' |
1437 | --- bin/addons/msf_profile/i18n/fr_MF.po 2019-06-20 14:24:33 +0000 |
1438 | +++ bin/addons/msf_profile/i18n/fr_MF.po 2019-07-15 07:18:58 +0000 |
1439 | @@ -8811,6 +8811,8 @@ |
1440 | #: selection:wizard.import.product.line,state:0 |
1441 | #: selection:product.mass.update,state:0 |
1442 | #: selection:stock.expired.damaged.report,state:0 |
1443 | +#: selection:account.invoice,counterpart_inv_status:0 |
1444 | +#: selection:wizard.account.invoice,counterpart_inv_status:0 |
1445 | #, python-format |
1446 | msgid "Draft" |
1447 | msgstr "Brouillon" |
1448 | @@ -10423,6 +10425,8 @@ |
1449 | #: selection:sale.donation.stock.moves,partner_type:0 |
1450 | #: selection:sale.loan.stock.moves,partner_type:0 |
1451 | #: selection:stock.picking,partner_type:0 |
1452 | +#: selection:account.invoice,partner_type:0 |
1453 | +#: selection:account.invoice.line,partner_type:0 |
1454 | #: code:addons/msf_supply_doc_export/wizard/supplier_performance_wizard.py:32 |
1455 | #: field:supplier.performance.wizard,partner_type_intermission:0 |
1456 | msgid "Intermission" |
1457 | @@ -11252,7 +11256,7 @@ |
1458 | |
1459 | #. module: account |
1460 | #: help:account.invoice.refund,filter_refund:0 |
1461 | -msgid "Refund invoice base on this type. You can not Modify and Cancel if the invoice is already reconciled" |
1462 | +msgid "Refund invoice based on this type. You can not Modify and Cancel if the invoice is already reconciled" |
1463 | msgstr "Facture d'Avoirs basée sur ce type. Vous ne pouvez pas Modifier ni Annuler si la facture est déjà lettrée." |
1464 | |
1465 | #. module: base |
1466 | @@ -12219,7 +12223,7 @@ |
1467 | msgid "No envoi.ini file found in given ZIP file!" |
1468 | msgstr "Pas de fichier envoi.ini trouvé dans le fichier ZP donné!" |
1469 | |
1470 | -#. modules: msf_processes, account, register_accounting |
1471 | +#. modules: msf_processes, account, register_accounting, account_override |
1472 | #: view:account.invoice:0 |
1473 | #: selection:account.invoice,type:0 |
1474 | #: selection:account.invoice.report,type:0 |
1475 | @@ -12233,6 +12237,7 @@ |
1476 | #: code:addons/register_accounting/account_bank_statement.py:2735 |
1477 | #: view:wizard.account.invoice:0 |
1478 | #: selection:wizard.account.invoice,type:0 |
1479 | +#: selection:account.invoice.line,invoice_type:0 |
1480 | #, python-format |
1481 | msgid "Supplier Invoice" |
1482 | msgstr "Facture Fournisseur" |
1483 | @@ -13330,7 +13335,7 @@ |
1484 | msgid "Automatic entry" |
1485 | msgstr "Ecriture Automatique" |
1486 | |
1487 | -#. modules: msf_order_date, purchase, msf_partner, stock_override, purchase_override, msf_config_locations, sale, account_override, analytic_distribution, msf_outgoing, msf_supply_doc_export |
1488 | +#. modules: msf_order_date, purchase, msf_partner, stock_override, purchase_override, msf_config_locations, sale, account_override, analytic_distribution, msf_outgoing, msf_supply_doc_export, account |
1489 | #: selection:shipment,partner_type:0 |
1490 | #: selection:purchase.order.merged.line,po_partner_type_stored:0 |
1491 | #: selection:sale.loan.stock.moves,partner_type:0 |
1492 | @@ -13348,6 +13353,8 @@ |
1493 | #: selection:sale.donation.stock.moves,partner_type:0 |
1494 | #: selection:sale.order.change.currency,partner_type:0 |
1495 | #: selection:stock.picking,partner_type_stock_picking:0 |
1496 | +#: selection:account.invoice,partner_type:0 |
1497 | +#: selection:account.invoice.line,partner_type:0 |
1498 | #: code:addons/msf_supply_doc_export/wizard/supplier_performance_wizard.py:30 |
1499 | #: field:supplier.performance.wizard,partner_type_external:0 |
1500 | msgid "External" |
1501 | @@ -14950,8 +14957,9 @@ |
1502 | msgid "BARBADOS DOLLAR" |
1503 | msgstr "BARBADOS DOLLAR" |
1504 | |
1505 | -#. modules: account, register_accounting |
1506 | +#. modules: account, register_accounting, account_override |
1507 | #: selection:account.invoice,type:0 |
1508 | +#: selection:account.invoice.line,invoice_type:0 |
1509 | #: selection:account.invoice.report,type:0 |
1510 | #: report:account.invoice2:0 |
1511 | #: selection:report.invoice.created,type:0 |
1512 | @@ -17436,12 +17444,13 @@ |
1513 | msgid "Warning!" |
1514 | msgstr "Avertissement!" |
1515 | |
1516 | -#. modules: purchase, sale |
1517 | +#. modules: purchase, sale, account_override |
1518 | #: code:addons/purchase/purchase_workflow.py:549 |
1519 | #: code:addons/sale/sale_workflow.py:529 |
1520 | +#: code:addons/account_override/invoice.py:829 |
1521 | #, python-format |
1522 | -msgid "You can't use taxes with an intermission partner." |
1523 | -msgstr "Vous ne pouvez pas utiliser de taxes avec un partenaire intermission." |
1524 | +msgid "Taxes are forbidden with Intermission and Intersection partners." |
1525 | +msgstr "Les taxes sont interdites avec les partenaires Intermission et Intersection." |
1526 | |
1527 | #. module: account |
1528 | #: model:ir.actions.act_window,name:account.action_account_fiscal_position_form |
1529 | @@ -21180,7 +21189,7 @@ |
1530 | msgid "Free 1 Lines" |
1531 | msgstr "Option 1 Lignes" |
1532 | |
1533 | -#. modules: account_override, msf_outgoing, purchase_override, stock_override, sale, msf_order_date, purchase, msf_partner, msf_supply_doc_export |
1534 | +#. modules: account_override, msf_outgoing, purchase_override, stock_override, sale, msf_order_date, purchase, msf_partner, msf_supply_doc_export, account |
1535 | #: field:account.account,has_partner_type_section:0 |
1536 | #: selection:shipment,partner_type:0 |
1537 | #: selection:purchase.order.merged.line,po_partner_type_stored:0 |
1538 | @@ -21188,6 +21197,8 @@ |
1539 | #: selection:sale.loan.stock.moves,partner_type:0 |
1540 | #: selection:stock.picking,partner_type:0 |
1541 | #: selection:sale.order,partner_type:0 |
1542 | +#: selection:account.invoice,partner_type:0 |
1543 | +#: selection:account.invoice.line,partner_type:0 |
1544 | #: view:res.partner:0 |
1545 | #: selection:res.partner,partner_type:0 |
1546 | #: selection:purchase.order,partner_type:0 |
1547 | @@ -27161,6 +27172,8 @@ |
1548 | #: field:purchase.report,invoiced:0 |
1549 | #: view:account.invoice:0 |
1550 | #: selection:account.direct.invoice.wizard,state:0 |
1551 | +#: selection:account.invoice,counterpart_inv_status:0 |
1552 | +#: selection:wizard.account.invoice,counterpart_inv_status:0 |
1553 | msgid "Paid" |
1554 | msgstr "Payé" |
1555 | |
1556 | @@ -45639,6 +45652,7 @@ |
1557 | |
1558 | #. modules: account, register_accounting |
1559 | #: field:account.invoice,tax_line:0 |
1560 | +#: field:account.invoice,tax_line_ids:0 |
1561 | #: field:wizard.account.invoice,tax_line:0 |
1562 | msgid "Tax Lines" |
1563 | msgstr "Lignes de Taxe" |
1564 | @@ -47234,7 +47248,7 @@ |
1565 | msgid "Metadata" |
1566 | msgstr "Métadonnées" |
1567 | |
1568 | -#. modules: msf_order_date, purchase, msf_outgoing, msf_partner, stock_override, purchase_override, sale, account_override, analytic_distribution, msf_supply_doc_export |
1569 | +#. modules: msf_order_date, purchase, msf_outgoing, msf_partner, stock_override, purchase_override, sale, account_override, analytic_distribution, msf_supply_doc_export, account |
1570 | #: field:account.account,has_partner_type_esc:0 |
1571 | #: view:account.commitment:0 |
1572 | #: selection:sale.order,partner_type:0 |
1573 | @@ -47250,6 +47264,8 @@ |
1574 | #: selection:sale.order.change.currency,partner_type:0 |
1575 | #: selection:stock.picking,partner_type:0 |
1576 | #: selection:stock.picking,partner_type_stock_picking:0 |
1577 | +#: selection:account.invoice,partner_type:0 |
1578 | +#: selection:account.invoice.line,partner_type:0 |
1579 | #: code:addons/msf_supply_doc_export/wizard/supplier_performance_wizard.py:31 |
1580 | #: field:supplier.performance.wizard,partner_type_esc:0 |
1581 | msgid "ESC" |
1582 | @@ -52060,9 +52076,11 @@ |
1583 | msgid "Search Donation" |
1584 | msgstr "Rechercher Donation" |
1585 | |
1586 | -#. module: sale |
1587 | +#. modules: sale, account_override, account |
1588 | #: report:addons/sale/report/sale_donation_stock_moves_report_xls.mako:127 |
1589 | #: field:sale.donation.stock.moves,partner_type:0 |
1590 | +#: field:account.invoice,partner_type:0 |
1591 | +#: field:account.invoice.line,partner_type:0 |
1592 | msgid "Partner Type" |
1593 | msgstr "Type de Partenaire" |
1594 | |
1595 | @@ -57043,8 +57061,9 @@ |
1596 | msgid "Kit Composition List" |
1597 | msgstr "Liste de composition du Kit" |
1598 | |
1599 | -#. modules: account, register_accounting |
1600 | +#. modules: account, register_accounting, account_override |
1601 | #: selection:account.invoice,type:0 |
1602 | +#: selection:account.invoice.line,invoice_type:0 |
1603 | #: selection:account.invoice.report,type:0 |
1604 | #: selection:report.invoice.created,type:0 |
1605 | #: selection:wizard.account.invoice,type:0 |
1606 | @@ -63480,6 +63499,18 @@ |
1607 | msgid "Cannot delete invoice(s) that are already opened or paid !" |
1608 | msgstr "Impossible de supprimer des factures qui sont déjà ouvertes ou payées !" |
1609 | |
1610 | +#. module: account |
1611 | +#: code:addons/account/invoice.py:472 |
1612 | +#, python-format |
1613 | +msgid "Cannot delete invoice(s) generated by a Supply workflow!" |
1614 | +msgstr "Impossible de supprimer des factures générées par un flux \"Supply\" !" |
1615 | + |
1616 | +#. module: account |
1617 | +#: code:addons/account/invoice.py:474 |
1618 | +#, python-format |
1619 | +msgid "Cannot delete invoice(s) set as \"Synchronized\"!" |
1620 | +msgstr "Impossible de supprimer des factures marquées comme \"Synchronisées\" !" |
1621 | + |
1622 | #. module: stock |
1623 | #: view:physical.inventory:0 |
1624 | msgid "Counting sheet" |
1625 | @@ -66467,8 +66498,9 @@ |
1626 | msgid "Remove all Instances" |
1627 | msgstr "Supprimer toutes les instances" |
1628 | |
1629 | -#. module: analytic_distribution |
1630 | +#. modules: analytic_distribution, account_override |
1631 | #: view:account.invoice.line:0 |
1632 | +#: view:account.invoice:0 |
1633 | msgid "Change analytic distribution" |
1634 | msgstr "Changer la distribution analytique" |
1635 | |
1636 | @@ -68529,7 +68561,7 @@ |
1637 | #. module: account_override |
1638 | #: view:account.invoice:0 |
1639 | msgid "You are about to cancel this invoice. Do you want to proceed?" |
1640 | -msgstr "You are about to cancel this invoice. Do you want to proceed?" |
1641 | +msgstr "Vous êtes sur le point d'annuler cette facture. Voulez-vous continuer ?" |
1642 | |
1643 | #. module: procurement |
1644 | #: help:procurement.order,name:0 |
1645 | @@ -73872,6 +73904,7 @@ |
1646 | #: code:addons/account_override/invoice.py:1484 |
1647 | #: code:addons/account_override/invoice.py:1772 |
1648 | #: code:addons/account_override/invoice.py:1775 |
1649 | +#: code:addons/account_override/account_invoice_sync.py:0 |
1650 | #: code:addons/account_reconciliation/account_move_line.py:236 |
1651 | #: code:addons/account_reconciliation/account_move_line.py:256 |
1652 | #: code:addons/account_reconciliation/account_move_line.py:258 |
1653 | @@ -78469,6 +78502,8 @@ |
1654 | #: selection:purchase.order,rfq_state:0 |
1655 | #: view:tender:0 |
1656 | #: selection:tender,state:0 |
1657 | +#: selection:account.invoice,counterpart_inv_status:0 |
1658 | +#: selection:wizard.account.invoice,counterpart_inv_status:0 |
1659 | #: field:po.follow.up,cancel_ok:0 |
1660 | #, python-format |
1661 | msgid "Cancelled" |
1662 | @@ -88640,6 +88675,8 @@ |
1663 | #: selection:wizard.import.cheque,state:0 |
1664 | #: selection:wizard.import.invoice,state:0 |
1665 | #: selection:wizard.register.creation,state:0 |
1666 | +#: selection:account.invoice,counterpart_inv_status:0 |
1667 | +#: selection:wizard.account.invoice,counterpart_inv_status:0 |
1668 | #, python-format |
1669 | msgid "Open" |
1670 | msgstr "Ouvert" |
1671 | @@ -89009,10 +89046,17 @@ |
1672 | |
1673 | #. module: account_override |
1674 | #: code:addons/account_override/invoice.py:747 |
1675 | +#: code:addons/account_override/account_invoice_sync.py:230 |
1676 | #, python-format |
1677 | msgid "No Intermission journal found for the current instance." |
1678 | msgstr "Pas de journal Intermission trouvé pour l'instance actuelle." |
1679 | |
1680 | +#. module: account_override |
1681 | +#: code:addons/account_override/account_invoice_sync.py:209 |
1682 | +#, python-format |
1683 | +msgid "No Purchase journal found for the current instance." |
1684 | +msgstr "Pas de journal des Achats trouvé pour l'instance actuelle." |
1685 | + |
1686 | #. module: msf_profile |
1687 | #: field:email.configuration,smtp_server:0 |
1688 | msgid "SMTP Server" |
1689 | @@ -94980,6 +95024,24 @@ |
1690 | msgid "Can not %s invoice which is already reconciled, invoice should be unreconciled first. You can only Refund this invoice" |
1691 | msgstr "Ne peut %s une facture qui est déjà lettrée, le lettrage de la facture devrait d'abord être annulé. Vous ne pouvez que Rembourser cette facture" |
1692 | |
1693 | +#. module: account |
1694 | +#: code:addons/account/wizard/account_invoice_refund.py:161 |
1695 | +#, python-format |
1696 | +msgid "Cannot %s an Intermission Voucher which is already reconciled, it should be unreconciled first." |
1697 | +msgstr "Ne peut %s un Bon Intermission qui est déjà lettré, le lettrage du bon devrait d'abord être annulé." |
1698 | + |
1699 | +#. module: account |
1700 | +#: code:addons/account/wizard/account_invoice_refund.py:0 |
1701 | +#, python-format |
1702 | +msgid "modify" |
1703 | +msgstr "modifier" |
1704 | + |
1705 | +#. module: account |
1706 | +#: code:addons/account/wizard/account_invoice_refund.py:0 |
1707 | +#, python-format |
1708 | +msgid "cancel" |
1709 | +msgstr "annuler" |
1710 | + |
1711 | #. modules: return_claim, msf_outgoing, stock_override, kit, msf_doc_import |
1712 | #: selection:assign.to.kit.line,integrity_status:0 |
1713 | #: selection:kit.selection.line,integrity_status:0 |
1714 | @@ -97634,7 +97696,7 @@ |
1715 | msgid "Document Date" |
1716 | msgstr "Date du Document" |
1717 | |
1718 | -#. modules: msf_order_date, purchase, msf_outgoing, stock_move_tracking, msf_partner, stock_override, purchase_override, msf_config_locations, sale, account_override, stock_batch_recall, specific_rules, msf_doc_import, stock, msf_supply_doc_export |
1719 | +#. modules: msf_order_date, purchase, msf_outgoing, stock_move_tracking, msf_partner, stock_override, purchase_override, msf_config_locations, sale, account_override, stock_batch_recall, specific_rules, msf_doc_import, stock, msf_supply_doc_export, account |
1720 | #: field:account.account,has_partner_type_internal:0 |
1721 | #: selection:stock.location.configuration.wizard,location_type:0 |
1722 | #: selection:stock.remove.location.wizard,location_usage:0 |
1723 | @@ -97663,6 +97725,8 @@ |
1724 | #: selection:stock.picking,fake_type:0 |
1725 | #: selection:stock.picking,partner_type:0 |
1726 | #: selection:stock.picking,partner_type_stock_picking:0 |
1727 | +#: selection:account.invoice,partner_type:0 |
1728 | +#: selection:account.invoice.line,partner_type:0 |
1729 | #: code:addons/msf_supply_doc_export/wizard/supplier_performance_wizard.py:28 |
1730 | #: field:supplier.performance.wizard,partner_type_internal:0 |
1731 | #, python-format |
1732 | @@ -101384,12 +101448,13 @@ |
1733 | msgid "On " |
1734 | msgstr "Allumé " |
1735 | |
1736 | -#. modules: account, register_accounting |
1737 | +#. modules: account, register_accounting, account_override |
1738 | #: selection:account.invoice,type:0 |
1739 | #: selection:account.invoice.report,type:0 |
1740 | #: model:process.process,name:account.process_process_invoiceprocess0 |
1741 | #: selection:report.invoice.created,type:0 |
1742 | #: selection:wizard.account.invoice,type:0 |
1743 | +#: selection:account.invoice.line,invoice_type:0 |
1744 | msgid "Customer Invoice" |
1745 | msgstr "Bon client" |
1746 | |
1747 | @@ -106827,3 +106892,167 @@ |
1748 | msgid "Stop report" |
1749 | msgstr "Arrêter le rapport" |
1750 | |
1751 | +#. module: account |
1752 | +#: field:account.invoice.refund,is_intermission:0 |
1753 | +msgid "Wizard opened from an Intermission Voucher" |
1754 | +msgstr "Assistant ouvert depuis un Bon Intermission" |
1755 | + |
1756 | +#. module: account_override |
1757 | +#: code:addons/account_override/invoice.py:1739 |
1758 | +#, python-format |
1759 | +msgid "This document has been generated via a Supply workflow or via synchronization. You can't add lines manually." |
1760 | +msgstr "Ce document a été généré via un flux \"Supply\" ou via la synchronisation. Vous ne pouvez pas ajouter de lignes manuellement." |
1761 | + |
1762 | +#. module: account_override |
1763 | +#: code:addons/account_override/invoice.py:1868 |
1764 | +#, python-format |
1765 | +msgid "This document has been generated via a Supply workflow or via synchronization. Existing lines can't be deleted." |
1766 | +msgstr "Ce document a été généré via un flux \"Supply\" ou via la synchronisation. Les lignes existantes ne peuvent pas être supprimées." |
1767 | + |
1768 | +#. module: account_override |
1769 | +#: code:addons/account_override/invoice.py:848 |
1770 | +#, python-format |
1771 | +msgid "Synchronized invoices are allowed only with Intermission and Intersection partners." |
1772 | +msgstr "Les factures synchronisées ne sont autorisées qu'avec les partenaires Intermission et Intersection." |
1773 | + |
1774 | +#. module: account |
1775 | +#: code:addons/account/invoice.py:683 |
1776 | +#, python-format |
1777 | +msgid "Synchronization is allowed only with Intermission and Intersection partners." |
1778 | +msgstr "La synchronisation n'est autorisée qu'avec les partenaires Intermission et Intersection." |
1779 | + |
1780 | +#. module: account_override |
1781 | +#: view:account.invoice:0 |
1782 | +msgid "Are you sure you want to validate this invoice without synchronization?" |
1783 | +msgstr "Etes-vous sûr de vouloir valider cette facture sans synchronisation ?" |
1784 | + |
1785 | +#. modules: account_override, account, register_accounting |
1786 | +#: view:account.invoice:0 |
1787 | +msgid "Counterpart Invoice" |
1788 | +msgstr "Facture de Contrepartie" |
1789 | + |
1790 | +#. modules: account_override, register_accounting |
1791 | +#: field:account.invoice,counterpart_inv_number:0 |
1792 | +#: field:wizard.account.invoice,counterpart_inv_number:0 |
1793 | +msgid "Counterpart Invoice Number" |
1794 | +msgstr "Numéro de la Facture de Contrepartie" |
1795 | + |
1796 | +#. modules: account_override, register_accounting |
1797 | +#: field:account.invoice,counterpart_inv_status:0 |
1798 | +#: field:wizard.account.invoice,counterpart_inv_status:0 |
1799 | +msgid "Counterpart Invoice Status" |
1800 | +msgstr "Etat de la Facture de Contrepartie" |
1801 | + |
1802 | +#. modules: account_override, register_accounting |
1803 | +#: field:account.invoice,synced:0 |
1804 | +#: field:wizard.account.invoice,synced:0 |
1805 | +#: field:account.invoice.line,synced:0 |
1806 | +msgid "Synchronized" |
1807 | +msgstr "Synchronisé" |
1808 | + |
1809 | +#. modules: account_override, register_accounting |
1810 | +#: field:account.invoice,from_supply:0 |
1811 | +#: field:wizard.account.invoice,from_supply:0 |
1812 | +#: field:account.invoice.line,from_supply:0 |
1813 | +msgid "From Supply" |
1814 | +msgstr "De la \"Supply\"" |
1815 | + |
1816 | +#. module: account_override |
1817 | +#: field:account.invoice.line,invoice_type:0 |
1818 | +msgid "Invoice Type" |
1819 | +msgstr "Type de Facture" |
1820 | + |
1821 | +#. modules: account_override, register_accounting |
1822 | +#: help:account.invoice,from_supply:0 |
1823 | +#: help:wizard.account.invoice,from_supply:0 |
1824 | +msgid "Internal field indicating whether the document is related to a Supply workflow" |
1825 | +msgstr "Champ interne indiquant si le document est lié à un flux \"Supply\"" |
1826 | + |
1827 | +#. module: account |
1828 | +#: help:account.invoice,tax_line_ids:0 |
1829 | +msgid "Internal field for taxes always in read-only mode" |
1830 | +msgstr "Champ interne pour les taxes toujours en mode lecture seule" |
1831 | + |
1832 | +#. module: account_override |
1833 | +#: code:addons/account_override/account_invoice_sync.py:120 |
1834 | +#, python-format |
1835 | +msgid "Account code %s not found." |
1836 | +msgstr "Code comptable %s non trouvé." |
1837 | + |
1838 | +#. module: account_override |
1839 | +#: code:addons/account_override/account_invoice_sync.py:189 |
1840 | +#, python-format |
1841 | +msgid "Impossible to retrieve the currency." |
1842 | +msgstr "Impossible de récupérer la devise." |
1843 | + |
1844 | +#. module: account_override |
1845 | +#: code:addons/account_override/account_invoice_sync.py:117 |
1846 | +#, python-format |
1847 | +msgid "Impossible to retrieve the account code at line level." |
1848 | +msgstr "Impossible de récupérer le code comptable au niveau d'une ligne." |
1849 | + |
1850 | +#. module: account_override |
1851 | +#: code:addons/account_override/account_invoice_sync.py:193 |
1852 | +#, python-format |
1853 | +msgid "Currency %s not found or inactive." |
1854 | +msgstr "Devise %s non trouvée ou inactive." |
1855 | + |
1856 | +#. module: account_override |
1857 | +#: code:addons/account_override/account_invoice_sync.py:123 |
1858 | +#, python-format |
1859 | +msgid "Error when retrieving the account at line level." |
1860 | +msgstr "Erreur lors de la récupération du compte au niveau d'une ligne." |
1861 | + |
1862 | +#. module: account_override |
1863 | +#: code:addons/account_override/account_invoice_sync.py:235 |
1864 | +#, python-format |
1865 | +msgid "The Intermission counterpart account is missing in the Company form or is inactive." |
1866 | +msgstr "Il manque le compte de Contrepartie Intermission dans le formulaire de la Société, ou bien ce compte est inactif." |
1867 | + |
1868 | +#. module: account_override |
1869 | +#: code:addons/account_override/account_invoice_sync.py:186 |
1870 | +#, python-format |
1871 | +msgid "Impossible to retrieve the journal type, or the journal type is incorrect." |
1872 | +msgstr "Impossible de récupérer le type de journal, ou le type de journal est incorrect." |
1873 | + |
1874 | +#. module: account_override |
1875 | +#: code:addons/account_override/account_invoice_sync.py:100 |
1876 | +#, python-format |
1877 | +msgid "Impossible to retrieve the line description." |
1878 | +msgstr "Impossible de récupérer la description de la ligne." |
1879 | + |
1880 | +#. module: account_override |
1881 | +#: code:addons/account_override/account_invoice_sync.py:128 |
1882 | +#, python-format |
1883 | +msgid "The account \"%s - %s\" is inactive." |
1884 | +msgstr "Le compte \"%s - %s\" est inactif." |
1885 | + |
1886 | +#. module: account_override |
1887 | +#: code:addons/account_override/account_invoice_sync.py:135 |
1888 | +#, python-format |
1889 | +msgid "Unit of Measure %s not found." |
1890 | +msgstr "Unité de Mesure %s non trouvée." |
1891 | + |
1892 | +#. module: account_override |
1893 | +#: code:addons/account_override/account_invoice_sync.py:109 |
1894 | +#, python-format |
1895 | +msgid "Product %s not found." |
1896 | +msgstr "Produit %s non trouvé." |
1897 | + |
1898 | +#. module: account_override |
1899 | +#: code:addons/account_override/account_invoice_sync.py:181 |
1900 | +#, python-format |
1901 | +msgid "The partner %s doesn't exist or is inactive." |
1902 | +msgstr "Le partenaire %s n'existe pas ou est inactif." |
1903 | + |
1904 | +#. module: account_override |
1905 | +#: code:addons/account_override/account_invoice_sync.py:113 |
1906 | +#, python-format |
1907 | +msgid "The product %s is inactive." |
1908 | +msgstr "Le produit %s est inactif." |
1909 | + |
1910 | +#. module: account_override |
1911 | +#: code:addons/account_override/account_invoice_sync.py:214 |
1912 | +#, python-format |
1913 | +msgid "Account Payable not found or inactive for the partner %s." |
1914 | +msgstr "Compte Fournisseur non trouvé ou inactif pour le partenaire %s." |
1915 | |
1916 | === modified file 'bin/addons/msf_profile/msf_profile.py' |
1917 | --- bin/addons/msf_profile/msf_profile.py 2019-06-20 14:28:17 +0000 |
1918 | +++ bin/addons/msf_profile/msf_profile.py 2019-07-15 07:18:58 +0000 |
1919 | @@ -69,6 +69,21 @@ |
1920 | err_msg, |
1921 | ) |
1922 | |
1923 | + # UF14.0 |
1924 | + def us_6076_set_inv_as_from_supply(self, cr, uid, *a, **b): |
1925 | + """ |
1926 | + Set the new tag from_supply to True in the related account.invoices |
1927 | + """ |
1928 | + update_inv = """ |
1929 | + UPDATE account_invoice |
1930 | + SET from_supply = 't' |
1931 | + WHERE picking_id IS NOT NULL |
1932 | + OR id IN (SELECT DISTINCT (invoice_id) FROM shipment WHERE invoice_id IS NOT NULL); |
1933 | + """ |
1934 | + cr.execute(update_inv) |
1935 | + self._logger.warn('Tag from_supply set to True in %s account.invoice(s).' % (cr.rowcount,)) |
1936 | + return True |
1937 | + |
1938 | # UF13.1 |
1939 | def us_3413_align_in_partner_to_po(self,cr, uid, *a, **b): |
1940 | cr.execute("select p.name, p.id, po.partner_id, p.partner_id from stock_picking p, purchase_order po where p.type='in' and po.id = p.purchase_id and ( p.partner_id != po.partner_id or p.partner_id2 != po.partner_id) order by p.name") |
1941 | |
1942 | === modified file 'bin/addons/msf_sync_data_server/data/sync_server.message_rule.csv' |
1943 | --- bin/addons/msf_sync_data_server/data/sync_server.message_rule.csv 2019-02-16 16:57:55 +0000 |
1944 | +++ bin/addons/msf_sync_data_server/data/sync_server.message_rule.csv 2019-07-15 07:18:58 +0000 |
1945 | @@ -15,6 +15,10 @@ |
1946 | msf_sync_data_server.validated_claim_create_claim,TRUE,TRUE,"['category_return_claim', 'creation_date_return_claim', 'description_return_claim', 'follow_up_return_claim', 'name', 'picking_id_return_claim/shipment_ref', 'po_id_return_claim/name', 'po_so_return_claim', 'goods_expected', 'processor_origin', 'state', 'type_return_claim', 'origin_claim', 'event_ids_return_claim/name', 'event_ids_return_claim/creation_date_claim_event', 'event_ids_return_claim/from_picking_wizard_claim_event', 'event_ids_return_claim/replacement_picking_expected_claim_event', 'event_ids_return_claim/type_claim_event', 'event_ids_return_claim/description_claim_event', 'product_line_ids_return_claim/price_unit_claim_product_line', 'product_line_ids_return_claim/qty_claim_product_line', 'product_line_ids_return_claim/product_id_claim_product_line/id', 'product_line_ids_return_claim/product_id_claim_product_line/name', 'product_line_ids_return_claim/price_currency_claim_product_line/id', 'product_line_ids_return_claim/price_currency_claim_product_line/name', 'product_line_ids_return_claim/uom_id_claim_product_line/id', 'product_line_ids_return_claim/uom_id_claim_product_line/name', 'product_line_ids_return_claim/type_check', 'product_line_ids_return_claim/expiry_date_claim_product_line']","[('state', '=', 'in_progress'), ('partner_id_return_claim.partner_type', 'in', ['internal', 'intermission', 'intersection']), ('type_return_claim', '=', 'supplier'), ('old_version', '=', False)]",partner_id_return_claim,MISSION,return.claim.validated_claim_create_claim,return.claim,Validated Claim creates Claim,28,,Valid |
1947 | msf_sync_data_server.origin_claim_close_claim,TRUE,TRUE,"['name', 'state', 'partner_id_return_claim/name', 'partner_id_return_claim/partner_type']","[('state', '=', 'done'), ('partner_id_return_claim.partner_type', '=', 'internal'), ('type_return_claim', '=', 'supplier'), ('old_version', '=', False)]",partner_id_return_claim,MISSION,return.claim.origin_claim_close_claim,return.claim,Original Closed Claim close counterpart Claim,29,,Valid |
1948 | msf_sync_data_server.goods_expecting_picking_from_claim_creates_fo,TRUE,TRUE,"['name', 'claim_name', 'purchase_id/name', 'purchase_id/delivery_requested_date','purchase_id/details', 'purchase_id/notes', 'purchase_id/categ', 'purchase_id/order_type', 'purchase_id/priority', 'purchase_id/loan_duration', 'purchase_id/analytic_distribution_id/id', 'purchase_id/is_a_counterpart', 'purchase_id/pricelist_id/name', 'purchase_id/stock_take_date', 'move_lines/product_id/name', 'move_lines/purchase_line_id/id', 'move_lines/purchase_line_id/sync_local_id', 'move_lines/name', 'move_lines/comment', 'move_lines/product_qty', 'move_lines/product_uom/name', 'move_lines/price_unit', 'move_lines/line_number']","['&', '&', ('state', '=', 'assigned'), ('partner_id.partner_type', '=', 'internal'), ('claim', '=', True), ('claim_name', '!=', False), '|', ('name', 'like', 'replacement'), ('name', 'like', 'missing')]",partner_id,MISSION,stock.picking.goods_expecting_picking_from_claim_creates_fo,stock.picking,IN-replacement/-missing created by Claim creates FO,30,,Valid |
1949 | +msf_sync_data_server.create_account_invoice,TRUE,TRUE,"['number', 'document_date', 'date_invoice', 'journal_id/type', 'name', 'origin', 'from_supply', 'state', 'currency_id/name', 'invoice_line/name', 'invoice_line/quantity', 'invoice_line/uos_id/name', 'invoice_line/price_unit', 'invoice_line/discount', 'invoice_line/account_id/code', 'invoice_line/product_id/id', 'invoice_line/product_id/default_code']","[('type', '=', 'out_invoice'), ('is_debit_note', '=', False), ('state', '!=', 'draft'), ('number', '!=', False), ('synced', '=', True), ('partner_type', 'in', ('intermission', 'section'))]",partner_id,MISSION,account.invoice.create_invoice_from_sync,account.invoice,Account Invoice Creation,40,,Valid |
1950 | +msf_sync_data_server.update_counterpart_inv_opened,TRUE,TRUE,"['number', 'state', 'counterpart_inv_number']","[('synced', '=', True), ('partner_type', 'in', ('intermission', 'section')), ('number', '!=', False), ('state', '=', 'open')]",partner_id,MISSION,account.invoice.update_counterpart_inv_opened,account.invoice,Account Invoice Open State Update,42,,Valid |
1951 | +msf_sync_data_server.update_counterpart_inv_paid,TRUE,TRUE,"['number', 'state', 'counterpart_inv_number']","[('synced', '=', True), ('partner_type', 'in', ('intermission', 'section')), ('number', '!=', False), ('state', '=', 'paid')]",partner_id,MISSION,account.invoice.update_counterpart_inv_paid,account.invoice,Account Invoice Paid State Update,43,,Valid |
1952 | +msf_sync_data_server.update_counterpart_inv_cancelled,TRUE,TRUE,"['number', 'state', 'counterpart_inv_number']","[('synced', '=', True), ('partner_type', 'in', ('intermission', 'section')), ('number', '!=', False), ('state', '=', 'cancel')]",partner_id,MISSION,account.invoice.update_counterpart_inv_cancelled,account.invoice,Account Invoice Cancel State Update,44,,Valid |
1953 | msf_sync_data_server.create_batch_object,FALSE,TRUE,"['name', 'xmlid_name', 'prefix', 'product_id/id', 'product_id/default_code', 'partner_id/id', 'date', 'ref','life_date','sequence_id','type']","[('name', '=', False)]",partner_id,MISSION,stock.picking.create_batch_number,stock.production.lot,Create Batch Object,1001,,Valid |
1954 | msf_sync_data_server.create_asset_object,TRUE,TRUE,"['name', 'xmlid_name', 'arrival_date', 'asset_type_id/id', 'partner_id/id', 'brand', 'comment', 'description', 'hq_ref', 'international_po', 'invo_certif_depreciation', 'invo_currency/id', 'invo_date', 'invo_donator_code', 'invo_num', 'invo_supplier', 'invo_value', 'local_ref', 'model', 'orig_mission_code', 'product_id/id', 'product_id/default_code', 'project_po', 'receipt_place', 'serial_nb', 'type', 'year']","[('name', '=', False)]",partner_id,MISSION,stock.picking.create_asset,product.asset,Create Asset Object,1002,,Valid |
1955 | msf_sync_data_server.reset_ref_by_recovery_mode,TRUE,TRUE,['name'],"[('name', '=', False)]",partner_id,MISSION,sale.order.reset_ref_by_recovery_mode,sale.order,Reset Due to Recovery,1003,,Valid |
1956 | |
1957 | === modified file 'bin/addons/purchase/purchase_workflow.py' |
1958 | --- bin/addons/purchase/purchase_workflow.py 2019-05-14 08:00:10 +0000 |
1959 | +++ bin/addons/purchase/purchase_workflow.py 2019-07-15 07:18:58 +0000 |
1960 | @@ -502,15 +502,15 @@ |
1961 | |
1962 | def check_po_tax(self, cr, uid, ids, context=None): |
1963 | """ |
1964 | - Prevents from validating a PO with taxes when using an Intermission partner |
1965 | + Prevents from validating a PO with taxes when using an Intermission or Intersection partner |
1966 | """ |
1967 | if context is None: |
1968 | context = {} |
1969 | if isinstance(ids, (int, long)): |
1970 | ids = [ids] |
1971 | for po_line in self.browse(cr, uid, ids, fields_to_fetch=['order_id', 'taxes_id'], context=context): |
1972 | - if po_line.taxes_id and po_line.order_id.partner_type == 'intermission': |
1973 | - raise osv.except_osv(_('Error'), _("You can't use taxes with an intermission partner.")) |
1974 | + if po_line.taxes_id and po_line.order_id.partner_type in ('intermission', 'section'): |
1975 | + raise osv.except_osv(_('Error'), _("Taxes are forbidden with Intermission and Intersection partners.")) |
1976 | |
1977 | def check_origin_for_validation(self, cr, uid, ids, context=None): |
1978 | if not context: |
1979 | |
1980 | === modified file 'bin/addons/register_accounting/account_invoice_view.xml' |
1981 | --- bin/addons/register_accounting/account_invoice_view.xml 2018-05-15 08:55:26 +0000 |
1982 | +++ bin/addons/register_accounting/account_invoice_view.xml 2019-07-15 07:18:58 +0000 |
1983 | @@ -316,11 +316,15 @@ |
1984 | </field> |
1985 | <xpath expr="/form/notebook/page[@string='Invoice']/field[@name='invoice_line']" position="before" > |
1986 | <group name="import" string=" Import Lines " colspan="4" col="4" attrs="{'invisible':[('state', '!=', 'draft')]}"> |
1987 | - <button name="wizard_import_si_line" string="Import lines" icon="gtk-dnd" type="object" attrs="{'invisible':[('state', '!=', 'draft')]}"/> |
1988 | + <button name="wizard_import_si_line" string="Import lines" icon="gtk-dnd" type="object" |
1989 | + attrs="{'invisible': [('state', '!=', 'draft')], |
1990 | + 'readonly': [('type', '=', 'in_invoice'), ('synced', '=', True)]}"/> |
1991 | </group> |
1992 | </xpath> |
1993 | <field name="journal_id" position="replace"> |
1994 | - <field name="journal_id" domain="[('is_current_instance','=',True), ('type', '=', context.get('journal_type'))]"/> |
1995 | + <field name="journal_id" |
1996 | + domain="[('is_current_instance','=',True), ('type', '=', context.get('journal_type'))]" |
1997 | + attrs="{'readonly': [('type', '=', 'in_invoice'), ('synced', '=', True)]}"/> |
1998 | <field name="vat_ok" invisible="1" /> |
1999 | </field> |
2000 | <button name="action_cancel_draft" position="replace"/> |
2001 | @@ -348,6 +352,14 @@ |
2002 | </tree> |
2003 | </field> |
2004 | </page> |
2005 | + <!-- display the Counterpart Invoice tab in SI, hide it in SR --> |
2006 | + <page string="Counterpart Invoice" attrs="{'invisible': [('type', '!=', 'in_invoice')]}"> |
2007 | + <field name="from_supply" invisible="1"/> <!-- make the field exportable --> |
2008 | + <field name="synced" readonly="1"/> <!-- SI can never be ticked as "Synced" manually --> |
2009 | + <newline/> |
2010 | + <field name="counterpart_inv_number"/> |
2011 | + <field name="counterpart_inv_status"/> |
2012 | + </page> |
2013 | </page> |
2014 | |
2015 | <xpath expr="/form//field[@name='tax_line']" position="attributes"> |
2016 | |
2017 | === modified file 'bin/addons/sale/sale_workflow.py' |
2018 | --- bin/addons/sale/sale_workflow.py 2019-05-14 08:00:10 +0000 |
2019 | +++ bin/addons/sale/sale_workflow.py 2019-07-15 07:18:58 +0000 |
2020 | @@ -529,15 +529,15 @@ |
2021 | |
2022 | def check_fo_tax(self, cr, uid, ids, context=None): |
2023 | """ |
2024 | - Prevents from validating a FO with taxes when using an Intermission partner |
2025 | + Prevents from validating a FO with taxes when using an Intermission or Intersection partner |
2026 | """ |
2027 | if context is None: |
2028 | context = {} |
2029 | if isinstance(ids, (int, long)): |
2030 | ids = [ids] |
2031 | for fo_line in self.browse(cr, uid, ids, fields_to_fetch=['order_id', 'tax_id'], context=context): |
2032 | - if fo_line.tax_id and fo_line.order_id.partner_type == 'intermission': |
2033 | - raise osv.except_osv(_('Error'), _("You can't use taxes with an intermission partner.")) |
2034 | + if fo_line.tax_id and fo_line.order_id.partner_type in ('intermission', 'section'): |
2035 | + raise osv.except_osv(_('Error'), _("Taxes are forbidden with Intermission and Intersection partners.")) |
2036 | |
2037 | def action_validate(self, cr, uid, ids, context=None): |
2038 | ''' |
2039 | |
2040 | === modified file 'bin/addons/stock/stock.py' |
2041 | --- bin/addons/stock/stock.py 2019-05-10 14:40:57 +0000 |
2042 | +++ bin/addons/stock/stock.py 2019-07-15 07:18:58 +0000 |
2043 | @@ -1228,6 +1228,7 @@ |
2044 | 'company_id': picking.company_id.id, |
2045 | 'user_id':uid, |
2046 | 'picking_id': picking.id, |
2047 | + 'from_supply': True, |
2048 | } |
2049 | if picking.sale_id: |
2050 | if not partner.property_account_position.id: |
2051 | @@ -1321,6 +1322,13 @@ |
2052 | if origin_ivi: |
2053 | invoice_vals.update({'origin': origin_ivi}) |
2054 | |
2055 | + # Add "synced" tag for STV and IVO created from Supply flow |
2056 | + out_invoice = inv_type == 'out_invoice' |
2057 | + is_stv = out_invoice and not di and not inkind_donation and not intermission |
2058 | + is_ivo = out_invoice and not debit_note and not inkind_donation and intermission |
2059 | + if is_stv or is_ivo: |
2060 | + invoice_vals.update({'synced': True, }) |
2061 | + |
2062 | # Update Payment terms and due date for the Supplier Invoices and Refunds |
2063 | if is_si or inv_type == 'in_refund': |
2064 | si_payment_term = self._get_payment_term(cr, uid, picking) |
2065 | |
2066 | === modified file 'bin/addons/stock_override/stock.py' |
2067 | --- bin/addons/stock_override/stock.py 2019-05-10 14:31:04 +0000 |
2068 | +++ bin/addons/stock_override/stock.py 2019-07-15 07:18:58 +0000 |
2069 | @@ -942,6 +942,11 @@ |
2070 | if sp.type == 'out' and sp.partner_id.partner_type == 'external' and invoice_type != 'in_refund': |
2071 | res = False |
2072 | |
2073 | + # Move in on an intermission or intersection partner should not create an IVI / SI (generation of Donations shouldn't be blocked) |
2074 | + if sp.type == 'in' and sp.purchase_id and sp.purchase_id.order_type not in ('donation_st', 'donation_exp') \ |
2075 | + and sp.partner_id and sp.partner_id.partner_type in ('intermission', 'section') and invoice_type == 'in_invoice': |
2076 | + res = False |
2077 | + |
2078 | return res |
2079 | |
2080 | def _create_invoice(self, cr, uid, stock_picking): |
2081 | |
2082 | === modified file 'bin/addons/sync_so/picking.py' |
2083 | --- bin/addons/sync_so/picking.py 2018-06-08 14:22:21 +0000 |
2084 | +++ bin/addons/sync_so/picking.py 2019-07-15 07:18:58 +0000 |
2085 | @@ -316,10 +316,7 @@ |
2086 | if shipment: |
2087 | shipment_ref = shipment['name'] # shipment made |
2088 | else: |
2089 | - #UFTP-332: Check if name is really an OUT, because DPO could have PICk but no SHIP nor OUT --> do not link this PICK to IN |
2090 | shipment_ref = pick_dict.get('name', False) # the case of OUT |
2091 | - if shipment_ref and 'OUT' not in shipment_ref: |
2092 | - shipment_ref = False |
2093 | if not po_id and pick_dict.get('sale_id') and pick_dict.get('sale_id', {}).get('claim_name_goods_return'): |
2094 | po_sync_name = pick_dict.get('sale_id', {}).get('client_order_ref') |
2095 | if po_sync_name: |
2096 | @@ -756,6 +753,9 @@ |
2097 | so_po_common = self.pool.get('so.po.common') |
2098 | so_po_common.create_invalid_recovery_message(cr, uid, source, in_name, context) |
2099 | return "Recovery: the reference to " + in_name + " at " + source + " will be set to void." |
2100 | + elif 'PICK' in out_doc_name: |
2101 | + return "Msg ignored" |
2102 | + |
2103 | if message: |
2104 | self._logger.info(message) |
2105 | return message |