Merge lp:~mallorymarcot/unifield-server/partial_dev into lp:unifield-server
- partial_dev
- Merge into trunk
Proposed by
jftempo
Status: | Rejected |
---|---|
Rejected by: | jftempo |
Proposed branch: | lp:~mallorymarcot/unifield-server/partial_dev |
Merge into: | lp:unifield-server |
Diff against target: |
35330 lines (+17188/-14622) 152 files modified
bin/addons/__init__.py (+19/-5) bin/addons/analytic_distribution/wizard/analytic_distribution_wizard.py (+5/-4) bin/addons/analytic_distribution_supply/purchase.py (+0/-12) bin/addons/analytic_distribution_supply/purchase_view.xml (+2/-2) bin/addons/analytic_distribution_supply/sale_view.xml (+2/-2) bin/addons/delete_button/view/sale_view.xml (+1/-1) bin/addons/delivery_mechanism/__openerp__.py (+0/-1) bin/addons/delivery_mechanism/delivery_mechanism.py (+50/-76) bin/addons/delivery_mechanism/wizard/enter_reason.py (+3/-1) bin/addons/documents_done/__openerp__.py (+1/-1) bin/addons/documents_done/documents_done.py (+5/-24) bin/addons/kit/wizard/kit_selection.py (+1/-12) bin/addons/msf_cross_docking/cross_docking.py (+2/-14) bin/addons/msf_cross_docking/cross_docking_view.xml (+0/-40) bin/addons/msf_custom_settings/view/purchase_view.xml (+20/-19) bin/addons/msf_custom_settings/view/sale_view.xml (+1/-1) bin/addons/msf_doc_import/__openerp__.py (+0/-2) bin/addons/msf_doc_import/view/purchase_order_import_line_view.xml (+54/-5) bin/addons/msf_doc_import/wizard/wizard_import_po_line.py (+1/-0) bin/addons/msf_doc_import/wizard/wizard_po_simulation_screen.py (+5/-1) bin/addons/msf_doc_import/workflow/procurement_request_workflow.xml (+3/-1) bin/addons/msf_doc_import/workflow/purchase_workflow.xml (+0/-11) bin/addons/msf_doc_import/workflow/sale_workflow.xml (+0/-8) bin/addons/msf_order_date/__openerp__.py (+1/-2) bin/addons/msf_order_date/order_dates.py (+3/-7) bin/addons/msf_order_date/order_dates_view.xml (+8/-8) bin/addons/msf_outgoing/msf_outgoing.py (+13/-27) bin/addons/msf_outgoing/msf_outgoing_view.xml (+1/-1) bin/addons/msf_processes/process/procurement_process.xml (+4/-4) bin/addons/msf_processes/process/purchase_process.xml (+4/-4) bin/addons/msf_processes/process/sale_process.xml (+4/-4) bin/addons/msf_profile/__openerp__.py (+1/-2) bin/addons/msf_profile/i18n/fr_MF.po (+1/-1) bin/addons/msf_profile/purchase_double_validation_workflow.xml (+0/-18) bin/addons/msf_profile/test/user_rights_test_files/user_rights_01_10-lines-removed_all-groups.xml (+3/-3) bin/addons/msf_profile/test/user_rights_test_files/user_rights_01_10-lines-removed_no-cashier_no-productManager.xml (+3/-3) bin/addons/msf_profile/test/user_rights_test_files/user_rights_01_all-lines_all-groups.xml (+3/-3) bin/addons/msf_profile/test/user_rights_test_files/user_rights_01_all-lines_all-groups_misformed_no-header.xml (+3/-3) bin/addons/msf_profile/test/user_rights_test_files/user_rights_01_all-lines_no-cashier_no-productManager.xml (+3/-3) bin/addons/msf_profile/test/user_rights_test_files/user_rights_01_all-lines_no-groups.xml (+3/-3) bin/addons/msf_profile/test/user_rights_test_files/user_rights_01_original.csv (+3/-3) bin/addons/msf_sync_data_server/data/sync_server.message_rule.csv (+5/-8) bin/addons/order_types/__openerp__.py (+0/-1) bin/addons/procurement_request/__openerp__.py (+7/-9) bin/addons/procurement_request/procurement_request.py (+8/-116) bin/addons/procurement_request/procurement_request_view.xml (+18/-16) bin/addons/procurement_request/procurement_request_workflow.xml (+0/-86) bin/addons/purchase/__init__.py (+3/-1) bin/addons/purchase/__openerp__.py (+3/-2) bin/addons/purchase/process/purchase_process.xml (+2/-1) bin/addons/purchase/procurement_order.py (+152/-0) bin/addons/purchase/purchase.py (+1612/-618) bin/addons/purchase/purchase_data.xml (+43/-2) bin/addons/purchase/purchase_line.py (+1422/-0) bin/addons/purchase/purchase_line_workflow.xml (+234/-0) bin/addons/purchase/purchase_view.xml (+202/-76) bin/addons/purchase/purchase_workflow.py (+566/-0) bin/addons/purchase/purchase_workflow.xml (+0/-209) bin/addons/purchase/wizard/__init__.py (+1/-0) bin/addons/purchase/wizard/purchase_line_cancel.py (+58/-0) bin/addons/purchase/wizard/purchase_line_cancel_view.xml (+24/-0) bin/addons/purchase_allocation_report/purchase_allocation_report.py (+2/-2) bin/addons/purchase_double_validation/__openerp__.py (+2/-3) bin/addons/purchase_double_validation/purchase_double_validation_workflow.xml (+0/-18) bin/addons/purchase_followup/sale_purchase.py (+10/-4) bin/addons/purchase_override/__init__.py (+28/-26) bin/addons/purchase_override/__openerp__.py (+0/-1) bin/addons/purchase_override/purchase.py (+16/-4360) bin/addons/purchase_override/purchase_view.xml (+0/-331) bin/addons/purchase_override/purchase_workflow.xml (+0/-163) bin/addons/purchase_override/wizard/split_order_line.py (+32/-170) bin/addons/register_accounting/__openerp__.py (+0/-1) bin/addons/register_accounting/purchase_view.xml (+0/-36) bin/addons/res_currency_functional/order_line_view.xml (+2/-2) bin/addons/return_claim/return_claim.py (+0/-1) bin/addons/sale/__init__.py (+25/-1) bin/addons/sale/__openerp__.py (+8/-2) bin/addons/sale/report/sale_report.py (+96/-22) bin/addons/sale/report/sale_report_view.xml (+63/-30) bin/addons/sale/res_partner.py (+95/-0) bin/addons/sale/sale_data.xml (+46/-4) bin/addons/sale/sale_order.py (+2737/-548) bin/addons/sale/sale_order_line_workflow.xml (+238/-0) bin/addons/sale/sale_sequence.xml (+4/-5) bin/addons/sale/sale_view.xml (+401/-44) bin/addons/sale/sale_workflow.py (+438/-0) bin/addons/sale/sale_workflow.xml (+0/-243) bin/addons/sale/test/data.yml (+170/-0) bin/addons/sale/test/deactivate_product_valid_fo.yml (+41/-0) bin/addons/sale/test/deactivate_product_validate_fo.yml (+49/-0) bin/addons/sale/test/sale_test.yml (+370/-0) bin/addons/sale/test/split_line.yml (+139/-0) bin/addons/sale/wizard/__init__.py (+3/-1) bin/addons/sale/wizard/delete_sale_order_line.py (+8/-6) bin/addons/sale/wizard/order_change_currency.py (+100/-0) bin/addons/sale/wizard/order_change_currency_view.xml (+27/-0) bin/addons/sale/wizard/split_order_line.py (+118/-0) bin/addons/sale/wizard/split_order_line_view.xml (+25/-0) bin/addons/sale_override/__init__.py (+0/-31) bin/addons/sale_override/__openerp__.py (+0/-55) bin/addons/sale_override/report/__init__.py (+0/-1) bin/addons/sale_override/report/sale_report.py (+0/-203) bin/addons/sale_override/report/sale_report_view.xml (+0/-144) bin/addons/sale_override/res_partner.py (+0/-95) bin/addons/sale_override/sale.py (+0/-3777) bin/addons/sale_override/sale_sequence.xml (+0/-19) bin/addons/sale_override/sale_view.xml (+0/-587) bin/addons/sale_override/sale_workflow.xml (+0/-143) bin/addons/sale_override/test/data.yml (+0/-170) bin/addons/sale_override/test/deactivate_product_valid_fo.yml (+0/-41) bin/addons/sale_override/test/deactivate_product_validate_fo.yml (+0/-49) bin/addons/sale_override/test/sale_test.yml (+0/-370) bin/addons/sale_override/test/split_line.yml (+0/-139) bin/addons/sale_override/wizard/__init__.py (+0/-3) bin/addons/sale_override/wizard/order_change_currency.py (+0/-100) bin/addons/sale_override/wizard/order_change_currency_view.xml (+0/-27) bin/addons/sale_override/wizard/split_order_line.py (+0/-103) bin/addons/sale_override/wizard/split_order_line_view.xml (+0/-25) bin/addons/sales_followup/report/sale_follow_up_report_multi.py (+5/-3) bin/addons/sales_followup/sale_followup.py (+21/-28) bin/addons/sourcing/__openerp__.py (+0/-1) bin/addons/sourcing/sale_order_line.py (+342/-15) bin/addons/sourcing/sourcing_view.xml (+6/-8) bin/addons/sourcing/wizard/multiple_sourcing.py (+6/-13) bin/addons/specific_locations/specific_locations.py (+0/-21) bin/addons/stock/stock.py (+12/-12) bin/addons/stock_override/stock.py (+32/-195) bin/addons/stock_override/stock_view.xml (+4/-3) bin/addons/sync_client/message.py (+32/-36) bin/addons/sync_client/sync_client.py (+1/-1) bin/addons/sync_server/__openerp__.py (+1/-1) bin/addons/sync_server/message.py (+0/-17) bin/addons/sync_server/sync_server_menu.xml (+1/-1) bin/addons/sync_so/purchase.py (+116/-295) bin/addons/sync_so/purchase_view.xml (+4/-4) bin/addons/sync_so/sale.py (+44/-0) bin/addons/sync_so/so_po_common.py (+127/-6) bin/addons/tender_flow/tender_flow.py (+164/-172) bin/addons/tender_flow/tender_flow_view.xml (+115/-56) bin/addons/tender_flow/tender_flow_workflow.xml (+2/-53) bin/addons/transport_mgmt/purchase_view.xml (+0/-26) bin/addons/unifield_tests/testfield/files/TC2 SSL VI import.xml (+329/-0) bin/addons/unifield_tests/testfield/init_data/set_rb_partial_tf.py (+114/-0) bin/addons/unifield_tests/testfield/meta_features/tc1.meta_feature (+1563/-0) bin/addons/unifield_tests/testfield/meta_features/tc1_intermission.meta_feature (+1577/-0) bin/addons/unifield_tests/testfield/meta_features/tc2.meta_feature (+924/-0) bin/addons/unifield_tests/testfield/meta_features/tc3.meta_feature (+1103/-0) bin/addons/unifield_tests/testfield/meta_features/tc4.meta_feature (+604/-0) bin/addons/useability_dashboard_and_menu/menu/warehouse_menu.xml (+1/-1) bin/addons/useability_dashboard_and_menu/view/purchase_view.xml (+2/-2) bin/addons/useability_dashboard_and_menu/view/sale_view.xml (+0/-25) bin/osv/orm.py (+47/-34) |
To merge this branch: | bzr merge lp:~mallorymarcot/unifield-server/partial_dev |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
UniField Reviewer Team | Pending | ||
Review via email: mp+331325@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
- 4658. By Mallory MARCOT
-
Adding tc1_intermission and tc4 fro testfield
- 4659. By Mallory MARCOT
-
tc1_intermission OK
- 4660. By Mallory MARCOT
-
Fix issue taking resourced state instead of real state
- 4661. By Mallory MARCOT
-
Can now cancel a PO from header
- 4662. By Mallory MARCOT
-
If PO line is in draft state, simply remove it instead of cancelling it
Unmerged revisions
- 4662. By Mallory MARCOT
-
If PO line is in draft state, simply remove it instead of cancelling it
- 4661. By Mallory MARCOT
-
Can now cancel a PO from header
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'bin/addons/__init__.py' |
2 | --- bin/addons/__init__.py 2016-08-31 07:58:29 +0000 |
3 | +++ bin/addons/__init__.py 2017-10-02 12:34:11 +0000 |
4 | @@ -409,9 +409,16 @@ |
5 | def init_module_objects(cr, module_name, obj_list): |
6 | logger.notifyChannel('init', netsvc.LOG_INFO, 'module %s: creating or updating database tables' % module_name) |
7 | todo = [] |
8 | + missing_fk = {} |
9 | for obj in obj_list: |
10 | try: |
11 | - result = obj._auto_init(cr, {'module': module_name}) |
12 | + auto_init = obj._auto_init(cr, {'module': module_name}) |
13 | + result = None |
14 | + if auto_init: |
15 | + result, fk = auto_init |
16 | + for obj, missing in fk.iteritems(): |
17 | + missing_fk.setdefault(obj, []) |
18 | + missing_fk[obj] += missing |
19 | except Exception, e: |
20 | raise |
21 | if result: |
22 | @@ -423,7 +430,7 @@ |
23 | for t in todo: |
24 | t[1](cr, *t[2]) |
25 | cr.commit() |
26 | - |
27 | + return missing_fk |
28 | |
29 | def register_class(m): |
30 | """ |
31 | @@ -512,7 +519,7 @@ |
32 | assert stage in ('pre', 'post') |
33 | stageformat = {'pre': '[>%s]', |
34 | 'post': '[%s>]', |
35 | - } |
36 | + } |
37 | |
38 | if not (hasattr(pkg, 'update') or pkg.state == 'to upgrade'): |
39 | return |
40 | @@ -541,7 +548,7 @@ |
41 | |
42 | mapping = {'module': opj(pkg.name, 'migrations'), |
43 | 'maintenance': opj('base', 'maintenance', 'migrations', pkg.name), |
44 | - } |
45 | + } |
46 | |
47 | for x in mapping.keys(): |
48 | if version in m[x]: |
49 | @@ -722,6 +729,7 @@ |
50 | modobj = None |
51 | logger.notifyChannel('init', netsvc.LOG_DEBUG, 'loading %d packages..' % len(graph)) |
52 | |
53 | + missing_fk = {} |
54 | for package in graph: |
55 | if skip_modules and package.name in skip_modules: |
56 | continue |
57 | @@ -730,9 +738,15 @@ |
58 | register_class(package.name) |
59 | modules = pool.instanciate(package.name, cr) |
60 | if hasattr(package, 'init') or hasattr(package, 'update') or package.state in ('to install', 'to upgrade'): |
61 | - init_module_objects(cr, package.name, modules) |
62 | + fk = init_module_objects(cr, package.name, modules) |
63 | + for obj, missing in fk.iteritems(): |
64 | + missing_fk.setdefault(obj, []) |
65 | + missing_fk[obj] += missing |
66 | cr.commit() |
67 | |
68 | + for related_obj, to_create in missing_fk.iteritems(): |
69 | + for x in to_create: |
70 | + x[0]._create_fk(cr, x[1], x[2], x[3]) |
71 | for package in graph: |
72 | status['progress'] = (float(statusi)+0.1) / len(graph) |
73 | m = package.name |
74 | |
75 | === modified file 'bin/addons/analytic_distribution/wizard/analytic_distribution_wizard.py' |
76 | --- bin/addons/analytic_distribution/wizard/analytic_distribution_wizard.py 2017-08-18 13:33:40 +0000 |
77 | +++ bin/addons/analytic_distribution/wizard/analytic_distribution_wizard.py 2017-10-02 12:34:11 +0000 |
78 | @@ -492,10 +492,10 @@ |
79 | for el in self.browse(cr, uid, ids, context=context): |
80 | res[el.id] = True |
81 | # verify purchase state |
82 | - if el.purchase_id and el.purchase_id.state not in ['draft', 'confirmed']: |
83 | + if el.purchase_id and el.purchase_id.state not in ['draft', 'draft_p', 'validated_n', 'validated']: |
84 | res[el.id] = False |
85 | # verify purchase line state |
86 | - if el.purchase_line_id and el.purchase_line_id.order_id and el.purchase_line_id.order_id.state not in ['draft', 'confirmed']: |
87 | + if el.purchase_line_id and el.purchase_line_id.order_id and el.purchase_line_id.order_id.state not in ['draft', 'validated_n', 'validated']: |
88 | res[el.id] = False |
89 | # verify invoice state |
90 | if el.invoice_id and el.invoice_id.state in ['open', 'paid']: |
91 | @@ -513,10 +513,10 @@ |
92 | if el.accrual_line_id and el.accrual_line_id.state != 'draft': |
93 | res[el.id] = False |
94 | # verify sale order state |
95 | - if el.sale_order_id and el.sale_order_id.state not in ['draft', 'validated']: |
96 | + if el.sale_order_id and el.sale_order_id.state not in ['draft', 'draft_p', 'validated']: |
97 | res[el.id] = False |
98 | # verify sale order line state |
99 | - if el.sale_order_line_id and el.sale_order_line_id.order_id and el.sale_order_line_id.order_id.state not in ['draft', 'validated']: |
100 | + if el.sale_order_line_id and el.sale_order_line_id.order_id and el.sale_order_line_id.order_id.state not in ['draft', 'draft_p', 'validated']: |
101 | res[el.id] = False |
102 | # verify move state |
103 | # UFTP-363: Do not edit any element of JI or JE if the JE is imported |
104 | @@ -1062,6 +1062,7 @@ |
105 | if getattr(wiz, el[0], False): |
106 | obj_id = getattr(wiz, el[0], False).id |
107 | self.pool.get(el[1]).write(cr, uid, [obj_id], {'analytic_distribution_id': distrib_id}, context=context) |
108 | + |
109 | # Finally do registration for each type |
110 | new_distrib = False |
111 | for line_type in ['cost.center', 'funding.pool', 'free.1', 'free.2']: |
112 | |
113 | === modified file 'bin/addons/analytic_distribution_supply/purchase.py' |
114 | --- bin/addons/analytic_distribution_supply/purchase.py 2017-02-07 13:18:54 +0000 |
115 | +++ bin/addons/analytic_distribution_supply/purchase.py 2017-10-02 12:34:11 +0000 |
116 | @@ -255,18 +255,6 @@ |
117 | self.pool.get('account.commitment').action_commitment_done(cr, uid, [x.id for x in po.commitment_ids], context=context) |
118 | return True |
119 | |
120 | - def wkf_action_cancel_po(self, cr, uid, ids, context=None): |
121 | - """ |
122 | - Delete commitment from purchase before 'cancel' state. |
123 | - """ |
124 | - # Some verifications |
125 | - if not context: |
126 | - context = {} |
127 | - if isinstance(ids, (int, long)): |
128 | - ids = [ids] |
129 | - # Change commitments state if exists |
130 | - self._finish_commitment(cr, uid, ids, context=context) |
131 | - return super(purchase_order, self).wkf_action_cancel_po(cr, uid, ids, context=context) |
132 | |
133 | def action_done(self, cr, uid, ids, context=None): |
134 | """ |
135 | |
136 | === modified file 'bin/addons/analytic_distribution_supply/purchase_view.xml' |
137 | --- bin/addons/analytic_distribution_supply/purchase_view.xml 2016-11-04 12:57:37 +0000 |
138 | +++ bin/addons/analytic_distribution_supply/purchase_view.xml 2017-10-02 12:34:11 +0000 |
139 | @@ -15,11 +15,11 @@ |
140 | <newline /> |
141 | <group colspan="4" col="8" attrs="{'invisible': ['|', ('analytic_distribution_id', '=', False), ('rfq_ok' ,'=', True)]}"> |
142 | <button name="button_analytic_distribution" string="Analytical Distribution" type="object" icon="terp-check" context="context" colspan="4" attrs="{'invisible': [('analytic_distribution_id', '=', False)]}"/> |
143 | - <button name="button_reset_distribution" string="Reset AD at line level" type="object" icon="gtk-undelete" colspan="4" states="draft,confirmed"/> |
144 | + <button name="button_reset_distribution" string="Reset AD at line level" type="object" icon="gtk-undelete" colspan="4" states="draft,validated"/> |
145 | </group> |
146 | <group colspan="4" col="8" attrs="{'invisible': ['|', ('analytic_distribution_id', '!=', False), ('rfq_ok', '=', True)]}"> |
147 | <button name="button_analytic_distribution" string="Analytical Distribution" type="object" icon="terp-emblem-important" context="context" colspan="4" attrs="{'invisible': [('analytic_distribution_id', '!=', False)]}"/> |
148 | - <button name="button_reset_distribution" string="Reset AD at line level" type="object" icon="gtk-undelete" colspan="4" states="draft,confirmed"/> |
149 | + <button name="button_reset_distribution" string="Reset AD at line level" type="object" icon="gtk-undelete" colspan="4" states="draft,validated"/> |
150 | </group> |
151 | <field name="analytic_distribution_id" invisible="1"/> |
152 | </xpath> |
153 | |
154 | === modified file 'bin/addons/analytic_distribution_supply/sale_view.xml' |
155 | --- bin/addons/analytic_distribution_supply/sale_view.xml 2016-11-04 12:57:37 +0000 |
156 | +++ bin/addons/analytic_distribution_supply/sale_view.xml 2017-10-02 12:34:11 +0000 |
157 | @@ -14,11 +14,11 @@ |
158 | <xpath expr="/form/notebook" position="before"> |
159 | <group colspan="4" col="8" attrs="{'invisible': [('analytic_distribution_id', '=', False)]}"> |
160 | <button name="button_analytic_distribution" string="Analytical Distribution" type="object" icon="terp-check" context="context" colspan="4" attrs="{'invisible': [('analytic_distribution_id', '=', False)]}"/> |
161 | - <button name="button_reset_distribution" string="Reset AD at line level" type="object" icon="gtk-undelete" colspan="4" states="draft,validated"/> |
162 | + <button name="button_reset_distribution" string="Reset AD at line level" type="object" icon="gtk-undelete" colspan="4" states="draft,draft_p,validated,validated_p"/> |
163 | </group> |
164 | <group colspan="4" col="8" attrs="{'invisible': [('analytic_distribution_id', '!=', False)]}"> |
165 | <button name="button_analytic_distribution" string="Analytical Distribution" type="object" icon="terp-emblem-important" context="context" colspan="4" attrs="{'invisible': [('analytic_distribution_id', '!=', False)]}"/> |
166 | - <button name="button_reset_distribution" string="Reset AD at line level" type="object" icon="gtk-undelete" colspan="4" states="draft,validated"/> |
167 | + <button name="button_reset_distribution" string="Reset AD at line level" type="object" icon="gtk-undelete" colspan="4" states="draft,draft_p,validated,validated_p"/> |
168 | </group> |
169 | <field name="analytic_distribution_id" invisible="1"/> |
170 | <group colspan="3"/> |
171 | |
172 | === modified file 'bin/addons/delete_button/view/sale_view.xml' |
173 | --- bin/addons/delete_button/view/sale_view.xml 2016-11-04 12:57:37 +0000 |
174 | +++ bin/addons/delete_button/view/sale_view.xml 2017-10-02 12:34:11 +0000 |
175 | @@ -29,7 +29,7 @@ |
176 | <xpath expr="/tree" position="attributes"> |
177 | <attribute name='hide_delete_button'>1</attribute> |
178 | </xpath> |
179 | - <xpath expr="/tree/field[@name='state_hidden_sale_order']" position="after"> |
180 | + <xpath expr="/tree/field[last()]" position="after"> |
181 | <button name="delete_button" type="object" icon="gtk-del" string="Delete" |
182 | attrs="{'invisible' : [('state','!=','draft')]}" confirm='Do you really want to delete selected record(s) ?'/> |
183 | </xpath> |
184 | |
185 | === modified file 'bin/addons/delivery_mechanism/__openerp__.py' |
186 | --- bin/addons/delivery_mechanism/__openerp__.py 2013-03-25 16:48:26 +0000 |
187 | +++ bin/addons/delivery_mechanism/__openerp__.py 2017-10-02 12:34:11 +0000 |
188 | @@ -28,7 +28,6 @@ |
189 | "account", |
190 | "stock_override", |
191 | "purchase_override", |
192 | - "sale_override", |
193 | "product_asset", # because of asset_id |
194 | "msf_outgoing", |
195 | ], |
196 | |
197 | === modified file 'bin/addons/delivery_mechanism/delivery_mechanism.py' |
198 | --- bin/addons/delivery_mechanism/delivery_mechanism.py 2017-09-03 15:15:05 +0000 |
199 | +++ bin/addons/delivery_mechanism/delivery_mechanism.py 2017-10-02 12:34:11 +0000 |
200 | @@ -257,11 +257,10 @@ |
201 | ''' |
202 | location_dest_id = super(stock_move, self)._get_location_for_internal_request(cr, uid, context=context, **kwargs) |
203 | move = kwargs['move'] |
204 | - if move.purchase_line_id: |
205 | - proc = move.purchase_line_id.procurement_id |
206 | - if proc and proc.sale_order_line_ids and proc.sale_order_line_ids[0].order_id and proc.sale_order_line_ids[0].order_id.procurement_request: |
207 | - if proc.sale_order_line_ids[0].order_id.location_requestor_id.usage != 'customer': |
208 | - location_dest_id = proc.sale_order_line_ids[0].order_id.location_requestor_id.id |
209 | + linked_sol = move.purchase_line_id.linked_sol_id or False |
210 | + if linked_sol and linked_sol.procurement_request and linked_sol.order_id.location_requestor_id.usage != 'customer': |
211 | + location_dest_id = linked_sol.order_id.location_requestor_id.id |
212 | + |
213 | return location_dest_id |
214 | |
215 | def _do_partial_hook(self, cr, uid, ids, context, *args, **kwargs): |
216 | @@ -303,56 +302,46 @@ |
217 | ids = [ids] |
218 | |
219 | # objects |
220 | - so_line_obj = self.pool.get('sale.order.line') |
221 | - |
222 | res = {} |
223 | for obj in self.browse(cr, uid, ids, context=context, |
224 | fields_to_fetch=['picking_id', 'purchase_line_id', 'id']): |
225 | res[obj.id] = {'move_id': False, 'picking_id': False, 'picking_version': 0, 'quantity': 0, 'moves': []} |
226 | if obj.picking_id and obj.picking_id.type == 'in': |
227 | # we are looking for corresponding OUT move from sale order line |
228 | - if obj.purchase_line_id: |
229 | - # linekd to a po |
230 | - if obj.purchase_line_id.procurement_id: |
231 | - # on order |
232 | - procurement_id = obj.purchase_line_id.procurement_id.id |
233 | - # find the corresponding sale order line |
234 | - so_line_ids = so_line_obj.search(cr, uid, [('procurement_id', '=', procurement_id)], context=context) |
235 | - # if the procurement comes from replenishment rules, there will be a procurement, but no associated sale order line |
236 | - # we therefore do not raise an exception, but handle the case only if sale order lines are found |
237 | - if so_line_ids: |
238 | - # find the corresponding OUT move |
239 | - move_ids = self.search(cr, uid, [('product_id', '=', data_back['product_id']), |
240 | - ('state', 'in', ('assigned', 'confirmed')), |
241 | - ('sale_line_id', '=', so_line_ids[0]), |
242 | - ('in_out_updated', '=', False), |
243 | - ('picking_id.type', '=', 'out'), |
244 | - ('processed_stock_move', '=', False), |
245 | - ], order="state desc", context=context) |
246 | - # list of matching out moves |
247 | - integrity_check = [] |
248 | - for move in self.browse(cr, uid, move_ids, context=context): |
249 | - pick = move.picking_id |
250 | - cond1 = move.picking_id.subtype == 'standard' |
251 | - cond2 = move.product_qty != 0.00 and pick.subtype == 'picking' and (not pick.backorder_id or pick.backorder_id.subtype == 'standard') and pick.state == 'draft' |
252 | - if cond2 or cond1: |
253 | - integrity_check.append(move) |
254 | - # return the first one matching |
255 | - if integrity_check: |
256 | - if all([not move.processed_stock_move for move in integrity_check]): |
257 | - # the out stock moves (draft picking or std out) have not yet been processed, we can therefore update them |
258 | - res[obj.id].update({ |
259 | - 'move_id': integrity_check[0].id, |
260 | - 'moves': integrity_check, |
261 | - 'picking_id': integrity_check[0].picking_id.id, |
262 | - 'picking_version': integrity_check[0].picking_id.update_version_from_in_stock_picking, |
263 | - 'quantity': integrity_check[0].product_qty, |
264 | - }) |
265 | - else: |
266 | - # the corresponding OUT move have been processed completely or partially,, we do not update the OUT |
267 | - msg_log = _('The Stock Move %s from %s has already been processed and is ' |
268 | - 'therefore not updated.') % (integrity_check[0].name, integrity_check[0].picking_id.name) |
269 | - self.log(cr, uid, integrity_check[0].id, msg_log) |
270 | + if obj.purchase_line_id and obj.purchase_line_id.linked_sol_id: |
271 | + # find the corresponding OUT move |
272 | + move_ids = self.search(cr, uid, [('product_id', '=', data_back['product_id']), |
273 | + ('state', 'in', ('assigned', 'confirmed')), |
274 | + ('sale_line_id', '=', obj.purchase_line_id.linked_sol_id.id), |
275 | + ('in_out_updated', '=', False), |
276 | + ('picking_id.type', '=', 'out'), |
277 | + ('processed_stock_move', '=', False), |
278 | + ], order="state desc", context=context) |
279 | + # list of matching out moves |
280 | + integrity_check = [] |
281 | + for move in self.browse(cr, uid, move_ids, context=context): |
282 | + pick = move.picking_id |
283 | + cond1 = move.picking_id.subtype == 'standard' |
284 | + cond2 = move.product_qty != 0.00 and pick.subtype == 'picking' and (not pick.backorder_id or pick.backorder_id.subtype == 'standard') and pick.state == 'draft' |
285 | + # move from draft picking or standard picking |
286 | + if cond2 or cond1: |
287 | + integrity_check.append(move) |
288 | + # return the first one matching |
289 | + if integrity_check: |
290 | + if all([not move.processed_stock_move for move in integrity_check]): |
291 | + # the out stock moves (draft picking or std out) have not yet been processed, we can therefore update them |
292 | + res[obj.id].update({ |
293 | + 'move_id': integrity_check[0].id, |
294 | + 'moves': integrity_check, |
295 | + 'picking_id': integrity_check[0].picking_id.id, |
296 | + 'picking_version': integrity_check[0].picking_id.update_version_from_in_stock_picking, |
297 | + 'quantity': integrity_check[0].product_qty, |
298 | + }) |
299 | + else: |
300 | + # the corresponding OUT move have been processed completely or partially,, we do not update the OUT |
301 | + msg_log = _('The Stock Move %s from %s has already been processed and is ' |
302 | + 'therefore not updated.') % (integrity_check[0].name, integrity_check[0].picking_id.name) |
303 | + self.log(cr, uid, integrity_check[0].id, msg_log) |
304 | |
305 | else: |
306 | # we are looking for corresponding IN from on_order purchase order |
307 | @@ -632,9 +621,6 @@ |
308 | 'product_uos': data_back['product_uom'], |
309 | 'product_uos_qty': diff_qty, }, context=context) |
310 | move_obj.action_confirm(cr, uid, [new_move_id], context=context) |
311 | -# if present_qty == 0.00: |
312 | -# move_obj.write(cr, uid, [out_move_id], {'state': 'draft'}) |
313 | -# move_obj.unlink(cr, uid, out_move_id, context=context) |
314 | else: |
315 | move_obj.write(cr, uid, [out_move_id], {'product_qty': new_qty, |
316 | 'product_uom': data['product_uom'][0], |
317 | @@ -931,7 +917,6 @@ |
318 | # Objects |
319 | inc_proc_obj = self.pool.get('stock.incoming.processor') |
320 | move_proc_obj = self.pool.get('stock.move.in.processor') |
321 | - proc_obj = self.pool.get('procurement.order') |
322 | loc_obj = self.pool.get('stock.location') |
323 | uom_obj = self.pool.get('product.uom') |
324 | move_obj = self.pool.get('stock.move') |
325 | @@ -961,7 +946,6 @@ |
326 | backorder_id = False |
327 | |
328 | internal_loc = loc_obj.search(cr, uid, [('usage', '=', 'internal'), ('cross_docking_location_ok', '=', False)]) |
329 | - proc_loc_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'stock', 'location_procurement')[1] |
330 | context['location'] = internal_loc |
331 | |
332 | product_availability = {} |
333 | @@ -1182,6 +1166,10 @@ |
334 | # and the remaining quantity to list of moves to put in backorder |
335 | if diff_qty > 0.00 and move.state != 'cancel': |
336 | backordered_moves.append((move, diff_qty, average_values, data_back, move_sptc_values)) |
337 | + # decrement qty of linked INTernal move: |
338 | + internal_move = self.pool.get('stock.move').search(cr, uid, [('linked_incoming_move', '=', move.id)], context=context) |
339 | + if internal_move: |
340 | + move_obj.write(cr, uid, internal_move, {'product_qty': diff_qty, 'product_uos_qty': diff_qty}, context=context) |
341 | else: |
342 | for sptc_values in move_sptc_values: |
343 | # track change that will be created: |
344 | @@ -1190,20 +1178,10 @@ |
345 | 'transaction_name': _('Reception %s') % move.picking_id.name, |
346 | 'sptc_values': sptc_values.copy(), |
347 | }) |
348 | - |
349 | - # UTP-967 |
350 | - if move.state != 'cancel' and move.purchase_line_id and move.purchase_line_id.procurement_id: |
351 | - proc = move.purchase_line_id.procurement_id |
352 | - if proc.move_id and proc.move_id.location_id.id == proc_loc_id: |
353 | - if diff_qty > 0: |
354 | - # REF-59: move of partial in, |
355 | - # adapt proc order's move qty (for correct virtual stock) |
356 | - move_obj.write(cr, uid, [proc.move_id.id], |
357 | - {'product_qty': diff_qty}, context=context) |
358 | - else: |
359 | - proc_obj.write(cr, uid, [proc.id], {'move_id': move.id}, context=context) |
360 | - # note: do not close move until a diff qty is applied above |
361 | - move_obj.write(cr, uid, [proc.move_id.id], {'product_qty': 0.00, 'state': 'done'}, context=context) |
362 | + #Â cancel linked INTernal move (INT): |
363 | + internal_move = self.pool.get('stock.move').search(cr, uid, [('linked_incoming_move', '=', move.id)], context=context) |
364 | + if internal_move: |
365 | + move_obj.action_cancel(cr, uid, internal_move, context=context) |
366 | |
367 | prog_id = self.update_processing_info(cr, uid, picking_id, prog_id, { |
368 | 'progress_line': _('Done (%s/%s)') % (move_done, total_moves), |
369 | @@ -1286,8 +1264,11 @@ |
370 | bo_values.update(av_values) |
371 | context['keepLineNumber'] = True |
372 | context['from_button'] = False |
373 | - move_obj.copy(cr, uid, bo_move.id, bo_values, context=context) |
374 | + new_bo_move_id = move_obj.copy(cr, uid, bo_move.id, bo_values, context=context) |
375 | context['keepLineNumber'] = False |
376 | + # update linked INT move with new BO move id: |
377 | + internal_move = move_obj.search(cr, uid, [('linked_incoming_move', '=', bo_move.id)], context=context) |
378 | + move_obj.write(cr, uid, internal_move, {'linked_incoming_move': new_bo_move_id}, context=context) |
379 | |
380 | # Put the done moves in this new picking |
381 | done_values = {'picking_id': backorder_id} |
382 | @@ -1491,13 +1472,6 @@ |
383 | # If there are still some lines available with qty 0, then check if any in progress PICK, if all complete, then close the PICK |
384 | self.validate(cr, uid, [mirror_pick.id], context=context) |
385 | |
386 | - if move.purchase_line_id and move.purchase_line_id.procurement_id: |
387 | - procurement = move.purchase_line_id.procurement_id |
388 | - if not procurement.sale_id and procurement.move_id: |
389 | - self.pool.get('stock.move').action_cancel(cr, uid, [move.purchase_line_id.procurement_id.move_id.id]) |
390 | - wf_service.trg_validate(uid, 'procurement.order', move.purchase_line_id.procurement_id.id, 'button_cancel', cr) |
391 | - |
392 | - |
393 | # correct the corresponding po manually if exists - should be in shipping exception |
394 | if obj.purchase_id: |
395 | wf_service.trg_validate(uid, 'purchase.order', obj.purchase_id.id, 'picking_ok', cr) |
396 | |
397 | === modified file 'bin/addons/delivery_mechanism/wizard/enter_reason.py' |
398 | --- bin/addons/delivery_mechanism/wizard/enter_reason.py 2015-12-04 16:00:07 +0000 |
399 | +++ bin/addons/delivery_mechanism/wizard/enter_reason.py 2017-10-02 12:34:11 +0000 |
400 | @@ -80,7 +80,9 @@ |
401 | context['pol_qty'] = pol_qty |
402 | context['from_in_cancel'] = True |
403 | pol_obj.write(cr, uid, pol_ids, {'has_to_be_resourced': True}, context=context) |
404 | - pol_obj.cancel_sol(cr, uid, pol_ids, context=context) |
405 | + for pol in self.pool.get('purchase.order.line').browse(cr, uid, pol_ids, context=context): |
406 | + if pol.linked_sol_id: |
407 | + wf_service.trg_validate(uid, 'sale.order.line', pol.linked_sol_id.id, 'cancel', cr) |
408 | |
409 | # cancel the IN |
410 | wf_service.trg_validate(uid, 'stock.picking', obj.id, 'button_cancel', cr) |
411 | |
412 | === modified file 'bin/addons/documents_done/__openerp__.py' |
413 | --- bin/addons/documents_done/__openerp__.py 2011-12-30 09:19:57 +0000 |
414 | +++ bin/addons/documents_done/__openerp__.py 2017-10-02 12:34:11 +0000 |
415 | @@ -23,7 +23,7 @@ |
416 | "name": "Documents to Done", |
417 | "version": "1.0", |
418 | "depends": [ |
419 | - "sale_override", |
420 | + "sale", |
421 | "purchase_override", |
422 | "stock_override", |
423 | "tender_flow", |
424 | |
425 | === modified file 'bin/addons/documents_done/documents_done.py' |
426 | --- bin/addons/documents_done/documents_done.py 2017-04-19 10:05:42 +0000 |
427 | +++ bin/addons/documents_done/documents_done.py 2017-10-02 12:34:11 +0000 |
428 | @@ -130,30 +130,16 @@ |
429 | tender_ids = [] |
430 | invoice_ids = [] |
431 | for line in order.order_line: |
432 | - # Check procurement orders |
433 | - if line.procurement_id: |
434 | - if line.procurement_id.state not in ('cancel', 'done'): |
435 | - proc_ids.append(line.procurement_id.id) |
436 | - # Check PO |
437 | - if line.procurement_id.purchase_id and line.procurement_id.purchase_id.state not in ('cancel', 'done'): |
438 | - po_ids.append(line.procurement_id.purchase_id.id) |
439 | - #Â Check tenders |
440 | - if line.procurement_id.tender_id and line.procurement_id.tender_id.state not in ('cancel', 'done'): |
441 | - tender_ids.append(line.procurement_id.tender_id.id) |
442 | - #Â Check Rfheck RfQ |
443 | - for rfq in line.procurement_id.tender_id.rfq_ids: |
444 | - if rfq.state not in ('cancel', 'done'): |
445 | - po_ids.append(rfq.id) |
446 | + pol_id = self.pool.get('purchase.order.line').search(cr, uid, [('linked_sol_id', '=', line.id)], context=context) |
447 | + po_line = self.pool.get('purchase.order.line').browse(cr, uid, pol_id[0], context=context) if pol_id else False |
448 | + # Check PO |
449 | + if po_line and not po_line.state.startswith(('cancel', 'done')): |
450 | + po_ids.append(po_line.order_id.id) |
451 | |
452 | #Â Check loan counterpart |
453 | if order.loan_id and order.loan_id.state not in ('cancel', 'done'): |
454 | po_ids.append(order.loan_id.id) |
455 | |
456 | - #Â Invoices |
457 | - #for invoice in order.invoice_ids: |
458 | - # if invoice.state not in ('cancel', 'paid'): |
459 | - # invoice_ids.append(invoice.id) |
460 | - |
461 | if context.get('count', False): |
462 | return move_ids or proc_ids or po_ids or tender_ids or invoice_ids or False |
463 | else: |
464 | @@ -172,11 +158,6 @@ |
465 | if order.loan_id and order.loan_id.state not in ('cancel', 'done'): |
466 | so_ids.append(order.loan_id.id) |
467 | |
468 | - #Â Invoices |
469 | - #for invoice in order.invoice_ids: |
470 | - # if invoice.state not in ('cancel', 'paid'): |
471 | - # invoice_ids.append(invoice.id) |
472 | - |
473 | if context.get('count', False): |
474 | return move_ids or so_ids or invoice_ids or False |
475 | else: |
476 | |
477 | === modified file 'bin/addons/kit/wizard/kit_selection.py' |
478 | --- bin/addons/kit/wizard/kit_selection.py 2014-07-22 12:11:45 +0000 |
479 | +++ bin/addons/kit/wizard/kit_selection.py 2017-10-02 12:34:11 +0000 |
480 | @@ -225,18 +225,7 @@ |
481 | }) |
482 | # copy existing sol |
483 | last_line_id = sol_obj.copy(cr, uid, last_line_id, values, context=ctx_keep_info) |
484 | - # call the new procurement creation method |
485 | - so_obj.action_ship_proc_create(cr, uid, [obj.corresponding_so_id_kit_selection.id], context=context) |
486 | - # run the procurement, the make_po function detects the link to original po |
487 | - # and force merge the line to this po (even if it is not draft anymore) |
488 | - new_data_so = sol_obj.read(cr, uid, [last_line_id], ['procurement_id'], context=context) |
489 | - new_proc_id = new_data_so[0]['procurement_id'][0] |
490 | - wf_service.trg_validate(uid, 'procurement.order', new_proc_id, 'button_check', cr) |
491 | - # if original po line is confirmed, we action_confirm new line |
492 | - if obj.order_line_id_kit_selection.state == 'confirmed': |
493 | - # the correct line number according to new line number policy is set in po_line_values_hook of order_line_number/order_line_number.py/procurement_order |
494 | - new_po_ids = pol_obj.search(cr, uid, [('procurement_id', '=', new_proc_id)], context=context) |
495 | - pol_obj.action_confirm(cr, uid, new_po_ids, context=context) |
496 | + # /* code deletion for partial confirmation US-3185 */ |
497 | else: |
498 | # first item to be treated, we update the existing purchase order line |
499 | # sale order line will be updated when the Po is confirmed |
500 | |
501 | === modified file 'bin/addons/msf_cross_docking/cross_docking.py' |
502 | --- bin/addons/msf_cross_docking/cross_docking.py 2016-08-18 08:32:03 +0000 |
503 | +++ bin/addons/msf_cross_docking/cross_docking.py 2017-10-02 12:34:11 +0000 |
504 | @@ -39,7 +39,7 @@ |
505 | _columns = { |
506 | 'cross_docking_ok': fields.boolean('Cross docking'), |
507 | 'location_id': fields.many2one('stock.location', 'Destination', required=True, domain=[('usage', '<>', 'view')], |
508 | - help="""This location is set according to the Warehouse selected, or according to the option 'Cross docking' |
509 | + help="""This location is set according to the Warehouse selected, or according to the option 'Cross docking' |
510 | or freely if you do not select 'Warehouse'.But if the 'Order category' is set to 'Transport' or 'Service', |
511 | you cannot have an other location than 'Service'"""), |
512 | } |
513 | @@ -75,7 +75,7 @@ |
514 | warning = { |
515 | 'title': _('Warning'), |
516 | 'message': _('The IR lines to an internal location sourced by one of the lines of this PO will not affected by this modification'), |
517 | - } |
518 | + } |
519 | else: |
520 | warehouse_obj = self.pool.get('stock.warehouse') |
521 | if not warehouse_id: |
522 | @@ -113,16 +113,6 @@ |
523 | res['value']['cross_docking_ok'] = cross_docking_ok |
524 | return res |
525 | |
526 | - def onchange_warehouse_id(self, cr, uid, ids, warehouse_id, order_type, dest_address_id): |
527 | - """ Set cross_docking_ok to False when we change warehouse. |
528 | - @param warehouse_id: Changed id of warehouse. |
529 | - @return: Dictionary of values. |
530 | - """ |
531 | - res = super(purchase_order, self).onchange_warehouse_id(cr, uid, ids, warehouse_id, order_type, dest_address_id) |
532 | - if warehouse_id: |
533 | - res['value'].update({'cross_docking_ok': False}) |
534 | - return res |
535 | - |
536 | def onchange_categ(self, cr, uid, ids, category, warehouse_id, cross_docking_ok, location_id, context=None): |
537 | """ |
538 | Check if the list of products is valid for this new category |
539 | @@ -654,7 +644,6 @@ |
540 | todo.append(move.id) |
541 | self.infolog(cr, uid, "The source location of the stock move id:%s has been changed to cross-docking location" % (move.id)) |
542 | ret = True |
543 | - picking_todo = [] |
544 | if todo: |
545 | ret = self.write(cr, uid, todo, {'location_id': cross_docking_location, 'move_cross_docking_ok': True}, context=context) |
546 | |
547 | @@ -688,7 +677,6 @@ |
548 | ids = [ids] |
549 | obj_data = self.pool.get('ir.model.data') |
550 | todo = [] |
551 | - picking_todo = [] |
552 | for move in self.browse(cr, uid, ids, context=context): |
553 | if move.state != 'done': |
554 | ''' |
555 | |
556 | === modified file 'bin/addons/msf_cross_docking/cross_docking_view.xml' |
557 | --- bin/addons/msf_cross_docking/cross_docking_view.xml 2017-05-10 07:09:18 +0000 |
558 | +++ bin/addons/msf_cross_docking/cross_docking_view.xml 2017-10-02 12:34:11 +0000 |
559 | @@ -3,47 +3,7 @@ |
560 | <data> |
561 | |
562 | <!-- Here we just add a boolean in the page 'Delivery and invoicing' of the purchase order form notebook --> |
563 | - <record id="purchase_cross_docking_form_view2" model="ir.ui.view"> |
564 | - <field name="name">purchase.cross.docking.form.view2</field> |
565 | - <field name="model">purchase.order</field> |
566 | - <field name="type">form</field> |
567 | - <field name="priority">45</field> |
568 | - <field name="inherit_id" ref="purchase_override.purchase_order_type_form_view" /> |
569 | - <field name="arch" type="xml"> |
570 | - <data> |
571 | - <xpath expr="/form/group/field[@name='categ']" position="replace" > |
572 | - <field name="categ" on_change="onchange_categ(categ, warehouse_id, cross_docking_ok, location_id)" /> |
573 | - </xpath> |
574 | - </data> |
575 | - </field> |
576 | - </record> |
577 | |
578 | - <record id="purchase_cross_docking_form_view" model="ir.ui.view"> |
579 | - <field name="name">purchase.cross.docking.form.view</field> |
580 | - <field name="model">purchase.order</field> |
581 | - <field name="type">form</field> |
582 | - <field name="priority">25</field> |
583 | - <field name="inherit_id" ref="purchase.purchase_order_form" /> |
584 | - <field name="arch" type="xml"> |
585 | - <data> |
586 | - <xpath expr="/form/notebook/page[@string='Delivery & Invoicing']/group/field[@name='location_id']" position="before" > |
587 | - <field name="cross_docking_ok" |
588 | - attrs="{'readonly':['|', '|', '|', ('unallocation_ok', '=', True), ('order_type', '=', 'direct'), ('allocation_setup', '=', 'unallocated'), ('state', '!=', 'draft')]}" |
589 | - on_change="onchange_cross_docking_ok(cross_docking_ok, warehouse_id, categ)" |
590 | - /> |
591 | - </xpath> |
592 | - <field name="location_id" position= "replace"> |
593 | - <!-- attrs="{'readonly':['|', ('state', 'in', ['sourced', 'split', 'rfq_updated', 'done', 'cancel', 'confirmed', 'approved', 'except_picking', 'except_invoice', 'confirmed_wait']), '|',('cross_docking_ok','=', True), ('categ', 'in', ['service', 'transport'])], 'invisible': [('order_type', '=', 'direct')]}"--> |
594 | - <!-- [UF-1689] we want the user to select only Cross Docking or Input i.e. to tick or clear the checkbox cross docking |
595 | - so we set the location_id always readonly--> |
596 | - <field name="location_id" |
597 | - domain="[('usage', '=', 'internal')]" |
598 | - readonly="1" |
599 | - on_change="onchange_location_id(location_id,categ)"/> |
600 | - </field> |
601 | - </data> |
602 | - </field> |
603 | - </record> |
604 | |
605 | <!-- Here we add 'purchase_id' in the context for defining a 'default_get' |
606 | when we want to create a new stock move directly in the delivery form --> |
607 | |
608 | === modified file 'bin/addons/msf_custom_settings/view/purchase_view.xml' |
609 | --- bin/addons/msf_custom_settings/view/purchase_view.xml 2017-08-22 14:01:21 +0000 |
610 | +++ bin/addons/msf_custom_settings/view/purchase_view.xml 2017-10-02 12:34:11 +0000 |
611 | @@ -35,10 +35,10 @@ |
612 | <field name="canceled_end" invisible="1" /> |
613 | <field name="partner_id" on_change="onchange_partner_id(partner_id,date_order,est_transport_lead_time,context)" context="{'search_default_supplier':1}" |
614 | domain="[('supplier', '=', True), ('id', '!=', company_id), ('check_partner_po', '=', {'order_type':order_type, 'partner_id': partner_id, 'split_po': related_sourcing_id}), ('check_partner_rfq', '=', tender_id), ('partner_not_int', 'in', {'type':'po', 'ids':[active_id]})]" |
615 | - attrs="{'readonly': [('state', 'in', ['sourced', 'split', 'rfq_sent', 'rfq_updated', 'done', 'cancel', 'confirmed', 'confirmed_wait', 'approved', 'except_picking', 'except_invoice'])]}" /> |
616 | + attrs="{'readonly': [('state', 'in', ['sourced', 'split', 'rfq_sent', 'rfq_updated', 'done', 'cancel', 'validated', 'confirmed_wait', 'confirmed', 'except_picking', 'except_invoice'])]}" /> |
617 | <field name="partner_type" /> |
618 | - <field name="partner_address_id" attrs="{'readonly': [('state', 'in', ['sourced', 'split', 'rfq_sent', 'rfq_updated', 'done', 'cancel', 'confirmed_wait', 'approved', 'except_picking', 'except_invoice'])]}"/> |
619 | - <field name="origin" attrs="{'readonly': [('state', 'in', ['sourced', 'split', 'rfq_sent', 'rfq_updated', 'done', 'cancel', 'confirmed', 'confirmed_wait', 'approved', 'except_picking', 'except_invoice'])]}" widget="char"/> |
620 | + <field name="partner_address_id" attrs="{'readonly': [('state', 'in', ['sourced', 'split', 'rfq_sent', 'rfq_updated', 'done', 'cancel', 'confirmed_wait', 'confirmed', 'except_picking', 'except_invoice'])]}"/> |
621 | + <field name="origin" attrs="{'readonly': [('state', 'in', ['sourced', 'split', 'rfq_sent', 'rfq_updated', 'done', 'cancel', 'validated', 'confirmed_wait', 'confirmed', 'except_picking', 'except_invoice'])]}" widget="char"/> |
622 | <field name="internal_type" string="Zone" /> |
623 | <field name="customer_ref" widget="char" /> |
624 | <group colspan="2" col="3"> |
625 | @@ -47,7 +47,7 @@ |
626 | attrs="{'invisible': [('state', 'not in', ('draft', 'confirmed'))]}" /> |
627 | </group> |
628 | <field name="pricelist_id" string="Currency" domain="[('type', '=', 'purchase'), ('in_search', '=', partner_type)]" |
629 | - colspan="3" attrs="{'readonly': [('state', 'in', ['rfq_updated', 'done', 'cancel', 'confirmed_wait', 'approved', 'except_picking', 'except_invoice'])]}"/> |
630 | + colspan="3" attrs="{'readonly': [('state', 'in', ['rfq_updated', 'done', 'cancel', 'confirmed_wait', 'confirmed', 'except_picking', 'except_invoice'])]}"/> |
631 | </group> |
632 | </xpath> |
633 | <xpath expr="/form/notebook" position="after"> |
634 | @@ -85,36 +85,37 @@ |
635 | <newline/> |
636 | |
637 | <group colspan="4" col="16"> |
638 | - <field name="state" readonly="1"/> |
639 | + <field name="state" attrs="{'invisible': [('rfq_ok', '=', True)]}" readonly="1"/> |
640 | + <field name="rfq_state" attrs="{'invisible': [('rfq_ok', '=', False)]}" readonly="1"/> |
641 | <field name="from_procurement" invisible="1" /> |
642 | - <button name="dpo_received" string="Validate the reception" icon="terp-camera_test" |
643 | - attrs="{'invisible': ['|', ('state', '!=', 'approved'), ('order_type', '!=', 'direct')]}" /> |
644 | - <button name="purchase_cancel" type="object" |
645 | - attrs="{'invisible': ['|', ('state', 'not in', ['draft', 'confirmed', 'rfq_sent']), '&',('partner_type', 'not in', ('external', 'esc')), ('state', '=', 'confirmed')]}" |
646 | + <button name="close_lines" type="object" string="Validate the reception" icon="terp-camera_test" |
647 | + attrs="{'invisible': ['|', ('state', '!=', 'confirmed'), ('order_type', '!=', 'direct')]}" /> |
648 | + <button name="purchase_cancel" type="object" |
649 | + attrs="{'invisible': ['|', ('rfq_state', 'not in', ['draft', 'validated', 'sent']), '&',('partner_type', 'not in', ('external', 'esc')), ('state', '=', 'validated')]}" |
650 | string="Cancel" icon="gtk-cancel"/> |
651 | <button name="action_cancel_draft" states="cancel" string="Set to Draft" type="object" icon="gtk-convert" attrs="{'invisible': ['|', '|', '|', '|', '|', ('canceled_end', '=', True), ('po_from_fo', '=', True), ('po_from_ir', '=', True), ('po_from_rr', '=', True), ('tender_id', '!=', False), ('state', '!=', 'cancel')]}" /> |
652 | <!-- UTP-469 − Remove the cancel button |
653 | - <button name="action_cancel" states="approved,except_picking,except_invoice,wait" string="Cancel Purchase Order" type="object" icon="gtk-cancel" attrs="{'invisible': ['|', ('tender_id', '!=', False), ('state','not in', ['approved','except_picking','except_invoice','wait'])]}"/> --> |
654 | + <button name="action_cancel" states="approved,except_picking,except_invoice,wait" string="Cancel Purchase Order" type="object" icon="gtk-cancel" attrs="{'invisible': ['|', ('tender_id', '!=', False), ('state','not in', ['confirmed','except_picking','except_invoice','wait'])]}"/> --> |
655 | <button name="picking_ok" states="except_picking" string="Manually Corrected" icon="gtk-convert" attrs="{'invisible': ['|', ('tender_id', '!=', False), ('state', '!=', 'except_picking')]}"/> |
656 | <button name="invoice_ok" states="except_invoice" string="Manually Corrected" icon="gtk-convert" attrs="{'invisible': ['|', ('tender_id', '!=', False), ('state', '!=', 'except_invoice')]}"/> |
657 | <button name="purchase_appbuyer" states="wait_auth" string="Approve Purchase" icon="gtk-ok" attrs="{'invisible': ['|', ('tender_id', '!=', False), ('state', '!=', 'wait_auth')]}"/> |
658 | - <button name="confirm_button" states="confirmed" string="Confirm" icon="gtk-go-forward" type="object" /> |
659 | - <button name="purchase_confirm" states="draft" string="Validate" icon="gtk-go-forward" attrs="{'invisible': ['|', ('rfq_ok', '!=', False), ('state', '!=', 'draft')]}" /> |
660 | - <button name="rfq_sent" type="object" states="draft" string="Send RfQ" icon="gtk-go-forward" attrs="{'invisible': ['|', ('rfq_ok', '=', False), ('state', '!=', 'draft')]}" /> |
661 | - <button name="check_rfq_updated" type="object" states="rfq_sent" string="RfQ Updated" icon="gtk-go-forward" attrs="{'invisible': ['|', ('rfq_ok', '=', False), ('state', '!=', 'rfq_sent')]}" /> |
662 | - <button name="generate_po_from_rfq" states="done" type="object" string="Generate Po" icon="gtk-dnd-multiple" attrs="{'invisible': ['|', '|', ('tender_id', '!=', False), ('state', '!=', 'rfq_updated'), ('from_procurement', '=', True)], 'readonly': [('amount_total', '=', 0.00)]}" /> |
663 | - <button name="rfq_done" states="rfq_updated" string="RfQ Closed" icon="gtk-go-forward" attrs="{'invisible': ['|', '|', ('tender_id', '!=', False), ('state', '!=', 'rfq_updated'), ('from_procurement', '=', True)]}" /> |
664 | - <button name="rfq_done" states="rfq_updated" string="Continue sourcing" icon="gtk-go-forward" attrs="{'invisible': ['|', '|', ('tender_id', '!=', False), ('state', '!=', 'rfq_updated'), ('from_procurement', '=', False)]}" /> |
665 | + <button name="validate_lines" states="draft,draft_p" string="Validate lines" type="object" icon="gtk-go-forward"/> |
666 | + <button name="confirm_lines" states="validated,validated_p" string="Confirm lines" icon="gtk-go-forward" type="object" /> |
667 | + <button name="rfq_sent" type="object" string="Send RfQ" icon="gtk-go-forward" attrs="{'invisible': ['|', ('rfq_ok', '=', False), ('rfq_state', '!=', 'draft')]}" /> |
668 | + <button name="check_rfq_updated" type="object" string="RfQ Updated" icon="gtk-go-forward" attrs="{'invisible': ['|', ('rfq_ok', '=', False), ('rfq_state', '!=', 'sent')]}" /> |
669 | + <button name="generate_po_from_rfq" type="object" string="Generate Po" icon="gtk-dnd-multiple" attrs="{'invisible': ['|', '|', ('tender_id', '!=', False), ('rfq_state', '!=', 'updated'), ('from_procurement', '=', True)], 'readonly': [('amount_total', '=', 0.00)]}" /> |
670 | + <button name="rfq_done" string="RfQ Closed" icon="gtk-go-forward" attrs="{'invisible': ['|', '|', ('tender_id', '!=', False), ('rfq_state', '!=', 'updated'), ('from_procurement', '=', True)]}" /> |
671 | + <button name="rfq_done" string="Continue sourcing" icon="gtk-go-forward" attrs="{'invisible': ['|', '|', ('tender_id', '!=', False), ('rfq_state', '!=', 'updated'), ('from_procurement', '=', False)]}" /> |
672 | </group> |
673 | </xpath> |
674 | <xpath expr="/form//field[@name='pricelist_id']" position="replace"> |
675 | <group colspan="2" col="3"> |
676 | <field name="no_line" invisible="1" /> |
677 | <field name="pricelist_id" string="Currency" colspan="2" |
678 | - attrs="{'readonly': ['|', ('no_line', '=', False), ('state', 'in', ['rfq_updated', 'done', 'cancel', 'confirmed_wait', 'approved', 'except_picking', 'except_invoice'])]}" |
679 | + attrs="{'readonly': ['|', ('no_line', '=', False), ('state', 'in', ['rfq_updated', 'done', 'cancel', 'confirmed_wait', 'confirmed', 'except_picking', 'except_invoice'])]}" |
680 | domain="[('type', '=', 'purchase'), ('in_search', '=', partner_type)]" /> |
681 | <button name="change_currency" string="Change currency" icon="terp-dolar" type="object" |
682 | - attrs="{'invisible': ['|', ('no_line', '=', True), ('state', 'in', ['rfq_updated', 'done', 'cancel', 'confirmed_wait', 'approved', 'except_picking', 'except_invoice'])]}" /> |
683 | + attrs="{'invisible': ['|', ('no_line', '=', True), ('state', 'in', ['rfq_updated', 'done', 'cancel', 'confirmed_wait', 'confirmed', 'except_picking', 'except_invoice'])]}" /> |
684 | </group> |
685 | <button colspan="4" string="Round Qty to SoQ" type="object" name="round_to_soq" icon="gtk-execute" attrs="{'invisible': [('state', '!=', 'draft')]}" /> |
686 | </xpath> |
687 | |
688 | === modified file 'bin/addons/msf_custom_settings/view/sale_view.xml' |
689 | --- bin/addons/msf_custom_settings/view/sale_view.xml 2017-08-01 15:45:31 +0000 |
690 | +++ bin/addons/msf_custom_settings/view/sale_view.xml 2017-10-02 12:34:11 +0000 |
691 | @@ -53,7 +53,7 @@ |
692 | <button name="invoice_cancel" states="invoice_except" string="Cancel Order" icon="gtk-cancel"/> |
693 | <button name="order_confirm" states="validated" string="Confirm Order" icon="gtk-apply" invisible="True" /> |
694 | <button name="do_order_confirm_method" type="object" states="validated" string="Confirm Order" icon="gtk-apply" confirm="You are about to confirm the Field Order without going through the sourcing tool. Are you sure?" attrs="{'readonly': [('no_line', '=', True)]}" /> |
695 | - <button name="order_validated" string="Validate Order" icon="terp-check" states="draft" attrs="{'readonly': [('no_line', '=', True)]}" /> |
696 | + <button name="validate_lines" type="object" string="Validate Lines" icon="terp-check" states="draft,draft_p" attrs="{'readonly': [('no_line', '=', True)]}" /> |
697 | </group> |
698 | </xpath> |
699 | <xpath expr="/form//field[@name='pricelist_id']" position="replace"> |
700 | |
701 | === modified file 'bin/addons/msf_doc_import/__openerp__.py' |
702 | --- bin/addons/msf_doc_import/__openerp__.py 2017-05-22 16:04:34 +0000 |
703 | +++ bin/addons/msf_doc_import/__openerp__.py 2017-10-02 12:34:11 +0000 |
704 | @@ -70,8 +70,6 @@ |
705 | 'wizard/wiz_common_import_view.xml', |
706 | 'data/msf_doc_import_data.xml', |
707 | 'data/inactive_categ.xml', |
708 | - 'workflow/purchase_workflow.xml', |
709 | - 'workflow/sale_workflow.xml', |
710 | 'workflow/tender_flow_workflow.xml', |
711 | 'workflow/procurement_request_workflow.xml', |
712 | 'doc_import_report.xml', |
713 | |
714 | === modified file 'bin/addons/msf_doc_import/view/purchase_order_import_line_view.xml' |
715 | --- bin/addons/msf_doc_import/view/purchase_order_import_line_view.xml 2017-01-16 14:20:41 +0000 |
716 | +++ bin/addons/msf_doc_import/view/purchase_order_import_line_view.xml 2017-10-02 12:34:11 +0000 |
717 | @@ -42,9 +42,6 @@ |
718 | </field> |
719 | </xpath> |
720 | <xpath expr="/form/notebook/page[@string='Purchase Order']/field[@name='order_line']" position="before" > |
721 | - <button name="wizard_import_po_line" string="Import RfQ lines" icon="gtk-dnd" type="object" attrs="{'invisible':[('state', '!=', 'rfq_sent')]}"/> |
722 | - </xpath> |
723 | - <xpath expr="/form/notebook/page[@string='Purchase Order']/field[@name='order_line']" position="before" > |
724 | <group name="import" string=" Import Lines " colspan="1" col="4" attrs="{'invisible':[('state', '!=', 'draft')]}"> |
725 | <button name="wizard_import_po_line" string="Import lines" icon="gtk-dnd" col="1" type="object" attrs="{'invisible':[('state', '!=', 'draft')]}"/> |
726 | <button name="button_remove_lines" string="Delete Lines" icon="gtk-remove" colspan="1" type="object" attrs="{'invisible': ['|', ('po_from_fo', '=', True), ('po_from_ir', '=', True)]}" /> |
727 | @@ -52,8 +49,60 @@ |
728 | <button name="check_lines_to_fix" string="Check Lines" icon="gtk-dialog-warning" colspan="1" type="object" context="{'rfq_ok': rfq_ok}"/> |
729 | <button name="add_multiple_lines" string="Add multiple lines" icon="gtk-add" colspan="4" type="object" /> |
730 | </group> |
731 | - <button name="wizard_import_file" string="Import PO confirmation" icon="gtk-execute" colspan="1" type="object" attrs="{'invisible':[('state', '!=', 'confirmed')]}"/> |
732 | - <button name="export_po_integration" string="Export PO Validated" icon="gtk-execute" colspan="1" type="object" attrs="{'invisible':[('state', '!=', 'confirmed')]}"/> |
733 | + <button name="wizard_import_file" string="Import PO confirmation" icon="gtk-execute" colspan="1" type="object" attrs="{'invisible':[('state', 'not in', ['validated', 'validated_n', 'validated_p'])]}"/> |
734 | + <button name="export_po_integration" string="Export PO Validated" icon="gtk-execute" colspan="1" type="object" attrs="{'invisible':[('state', 'not in', ['validated', 'validated_n', 'validated_p'])]}"/> |
735 | + </xpath> |
736 | + </data> |
737 | + </field> |
738 | + </record> |
739 | + |
740 | + <record id="rfq_form_import" model="ir.ui.view"> |
741 | + <field name="name">rfq.form.import</field> |
742 | + <field name="model">purchase.order</field> |
743 | + <field name="type">form</field> |
744 | + <field name="priority">110</field> |
745 | + <field name="inherit_id" ref="tender_flow.view_rfq_form" /> |
746 | + <field name="arch" type="xml"> |
747 | + <data> |
748 | + <xpath expr="/form" position="attributes"> |
749 | + <attribute name="noteditable">import_in_progress==True or update_in_progress==True</attribute> |
750 | + </xpath> |
751 | + <xpath expr="/form//field" position="before"> |
752 | + <field name="update_in_progress" invisible="1" readonly="1" /> |
753 | + </xpath> |
754 | + |
755 | + <xpath expr="/form/notebook/page/field[@name='order_line']/tree/field[@name='currency_id']" position="after"> |
756 | + <field name="to_correct_ok" invisible="1"/> |
757 | + </xpath> |
758 | + <xpath expr="/form/notebook/page/field[@name='order_line']/tree//field[@name='default_name']" position="after"> |
759 | + <field name="inactive_product" invisible="1" /> |
760 | + <field name="soq_updated" invisible="1" readonly="1" /> |
761 | + </xpath> |
762 | + <xpath expr="/form/notebook/page/field[@name='order_line']/tree" position="attributes" > |
763 | + <attribute name="colors">red:to_correct_ok == True or inactive_product == True or red_color == True; #C8C8C8: fake_state == 'cancel'; orange:product_qty == 0.00;blue: soq_updated == True</attribute> |
764 | + </xpath> |
765 | + <xpath expr="/form/notebook/page[@string='Notes']/field[@name='notes']" position="before"> |
766 | + <field name="import_in_progress" readonly="1" invisible="0" /> |
767 | + </xpath> |
768 | + <xpath expr="/form/notebook/page[@string='Notes']/field[@name='project_ref']" position="after"> |
769 | + <separator colspan="4" string="Sourcing group" /> |
770 | + <field name="related_sourcing_id" readonly="True" /> |
771 | + <separator colspan="4" string="Import filenames" /> |
772 | + <field name="import_filenames" mode="tree" readonly="1" nolabel="1" colspan="4"> |
773 | + <tree string="Imported filenames"> |
774 | + <field name="timestamp" /> |
775 | + <field name="filename" /> |
776 | + </tree> |
777 | + </field> |
778 | + </xpath> |
779 | + <xpath expr="/form/notebook/page/field[@name='order_line']" position="before" > |
780 | + <group name="import" string=" Import Lines " colspan="4" attrs="{'invisible':[('rfq_state', '!=', 'draft')]}"> |
781 | + <button name="wizard_import_po_line" string="Import lines" icon="gtk-dnd" col="1" type="object"/> |
782 | + <button name="button_remove_lines" string="Delete Lines" icon="gtk-remove" colspan="1" type="object" attrs="{'invisible': ['|', ('po_from_fo', '=', True), ('po_from_ir', '=', True)]}" /> |
783 | + <button name="button_remove_lines" string="Delete Lines" confirm="This document originated from an IR/FO, if you delete these products now, they will all be deleted. If you wish to Cancel & Resource them, please do this line by line." icon="gtk-remove" colspan="1" type="object" attrs="{'invisible': [('po_from_fo', '=', False), ('po_from_ir', '=', False)]}" /> |
784 | + <button name="check_lines_to_fix" string="Check Lines" icon="gtk-dialog-warning" colspan="1" type="object" context="{'rfq_ok': rfq_ok}"/> |
785 | + <button name="add_multiple_lines" string="Add multiple lines" icon="gtk-add" colspan="4" type="object" /> |
786 | + </group> |
787 | </xpath> |
788 | </data> |
789 | </field> |
790 | |
791 | === modified file 'bin/addons/msf_doc_import/wizard/wizard_import_po_line.py' |
792 | --- bin/addons/msf_doc_import/wizard/wizard_import_po_line.py 2016-12-06 11:15:12 +0000 |
793 | +++ bin/addons/msf_doc_import/wizard/wizard_import_po_line.py 2017-10-02 12:34:11 +0000 |
794 | @@ -163,6 +163,7 @@ |
795 | 'default_code': False, |
796 | 'confirmed_delivery_date': False, |
797 | 'line_number': '', |
798 | + 'set_as_validated_n': True, |
799 | } |
800 | |
801 | col_count = len(row) |
802 | |
803 | === modified file 'bin/addons/msf_doc_import/wizard/wizard_po_simulation_screen.py' |
804 | --- bin/addons/msf_doc_import/wizard/wizard_po_simulation_screen.py 2016-12-05 09:13:30 +0000 |
805 | +++ bin/addons/msf_doc_import/wizard/wizard_po_simulation_screen.py 2017-10-02 12:34:11 +0000 |
806 | @@ -29,6 +29,7 @@ |
807 | from lxml.etree import XMLSyntaxError |
808 | import logging |
809 | import os |
810 | +import netsvc |
811 | |
812 | from mx import DateTime |
813 | |
814 | @@ -1540,6 +1541,7 @@ |
815 | line_obj = self.pool.get('purchase.order.line') |
816 | split_obj = self.pool.get('split.purchase.order.line.wizard') |
817 | simu_obj = self.pool.get('wizard.import.po.simulation.screen') |
818 | + wf_service = netsvc.LocalService("workflow") |
819 | |
820 | if context is None: |
821 | context = {} |
822 | @@ -1561,7 +1563,7 @@ |
823 | # Don't do anything |
824 | continue |
825 | elif line.type_change == 'del' and line.po_line_id: |
826 | - line_obj.fake_unlink(cr, uid, [line.po_line_id.id], context=context) |
827 | + wf_service.trg_validate(uid, 'purchase.order.line', line.po_line_id.id, 'cancel', cr) |
828 | elif line.type_change == 'split' and line.parent_line_id: |
829 | # Call the split line wizard |
830 | po_line_id = False |
831 | @@ -1596,6 +1598,7 @@ |
832 | line_vals = {'product_uom': line.imp_uom.id, |
833 | 'product_id': line.imp_product_id.id, |
834 | 'price_unit': line.imp_price, |
835 | + 'set_as_validated_n': True, |
836 | } |
837 | if line.imp_drd: |
838 | line_vals['date_planned'] = line.imp_drd |
839 | @@ -1641,6 +1644,7 @@ |
840 | 'price_unit': line.imp_price, |
841 | 'product_qty': line.imp_qty, |
842 | 'date_planned': line.imp_drd or line.simu_id.order_id.delivery_requested_date, |
843 | + 'set_as_validated_n': True, |
844 | } |
845 | if line.imp_dcd: |
846 | line_vals['confirmed_delivery_date'] = line.imp_dcd |
847 | |
848 | === modified file 'bin/addons/msf_doc_import/workflow/procurement_request_workflow.xml' |
849 | --- bin/addons/msf_doc_import/workflow/procurement_request_workflow.xml 2012-07-20 13:52:00 +0000 |
850 | +++ bin/addons/msf_doc_import/workflow/procurement_request_workflow.xml 2017-10-02 12:34:11 +0000 |
851 | @@ -7,11 +7,13 @@ |
852 | |
853 | <!-- We redefined this transition to enhance the coverage of the condition --> |
854 | |
855 | +<!-- |
856 | <record id="procurement_request.trans_proc_validate" model="workflow.transition"> |
857 | <field name="act_from" ref="procurement_request.act_procurement"/> |
858 | <field name="act_to" ref="procurement_request.act_proc_validate"/> |
859 | <field name="signal">procurement_validate</field> |
860 | <field name="condition">procurement_request==True and check_lines_to_fix()</field> |
861 | </record> |
862 | +--> |
863 | </data> |
864 | -</openerp> |
865 | \ No newline at end of file |
866 | +</openerp> |
867 | |
868 | === removed file 'bin/addons/msf_doc_import/workflow/purchase_workflow.xml' |
869 | --- bin/addons/msf_doc_import/workflow/purchase_workflow.xml 2013-05-08 08:57:30 +0000 |
870 | +++ bin/addons/msf_doc_import/workflow/purchase_workflow.xml 1970-01-01 00:00:00 +0000 |
871 | @@ -1,11 +0,0 @@ |
872 | -<?xml version="1.0" encoding="utf-8"?> |
873 | -<openerp> |
874 | - <data> |
875 | - <record id="purchase.trans_draft_confirmed" model="workflow.transition"> |
876 | - <field name="condition">check_lines_to_fix()</field> |
877 | - </record> |
878 | - <record id="purchase.trans_confirmed_cancel" model="workflow.transition"> |
879 | - <field name="condition">check_condition()</field> |
880 | - </record> |
881 | - </data> |
882 | -</openerp> |
883 | \ No newline at end of file |
884 | |
885 | === removed file 'bin/addons/msf_doc_import/workflow/sale_workflow.xml' |
886 | --- bin/addons/msf_doc_import/workflow/sale_workflow.xml 2012-07-20 13:52:00 +0000 |
887 | +++ bin/addons/msf_doc_import/workflow/sale_workflow.xml 1970-01-01 00:00:00 +0000 |
888 | @@ -1,8 +0,0 @@ |
889 | -<?xml version="1.0" encoding="utf-8"?> |
890 | -<openerp> |
891 | - <data> |
892 | - <record id="sale_override.trans_draft_validated" model="workflow.transition"> |
893 | - <field name="condition">check_lines_to_fix()</field> |
894 | - </record> |
895 | - </data> |
896 | -</openerp> |
897 | \ No newline at end of file |
898 | |
899 | === modified file 'bin/addons/msf_order_date/__openerp__.py' |
900 | --- bin/addons/msf_order_date/__openerp__.py 2012-02-27 16:26:55 +0000 |
901 | +++ bin/addons/msf_order_date/__openerp__.py 2017-10-02 12:34:11 +0000 |
902 | @@ -23,11 +23,10 @@ |
903 | "name": "MSF Order dates", |
904 | "version": "3.0", |
905 | "depends": ["base", |
906 | - "sale", |
907 | "purchase", |
908 | "account", |
909 | "stock_override", |
910 | - "sale_override", |
911 | + "sale", |
912 | "purchase_override", |
913 | "partner_modification", |
914 | "msf_tools", |
915 | |
916 | === modified file 'bin/addons/msf_order_date/order_dates.py' |
917 | --- bin/addons/msf_order_date/order_dates.py 2017-08-25 15:37:51 +0000 |
918 | +++ bin/addons/msf_order_date/order_dates.py 2017-10-02 12:34:11 +0000 |
919 | @@ -32,7 +32,7 @@ |
920 | from msf_order_date import TRANSPORT_TYPE |
921 | from msf_order_date import ZONE_SELECTION |
922 | from purchase_override import PURCHASE_ORDER_STATE_SELECTION |
923 | -from sale_override import SALE_ORDER_STATE_SELECTION |
924 | +from sale import SALE_ORDER_STATE_SELECTION |
925 | |
926 | class res_partner(osv.osv): |
927 | _name = 'res.partner' |
928 | @@ -437,13 +437,7 @@ |
929 | if context is None: |
930 | context = {} |
931 | |
932 | - order_id = context.get('active_id', []) |
933 | - if isinstance(order_id, (int, long)): |
934 | - order_id = [order_id] |
935 | - |
936 | - |
937 | return {'value': {'date_planned': requested_date, }} |
938 | -# 'confirmed_delivery_date': confirmed_date}} |
939 | |
940 | def common_create(self, cr, uid, data, type, context=None): |
941 | ''' |
942 | @@ -929,6 +923,8 @@ |
943 | |
944 | for order in self.browse(cr, uid, ids, context=context): |
945 | # Fill partner type |
946 | + if data.get('partner_id') and isinstance(data.get('partner_id'), basestring): |
947 | + data['partner_id'] = int(data.get('partner_id')) |
948 | partner = self.pool.get('res.partner').browse(cr, uid, data.get('partner_id', order.partner_id.id), context=context) |
949 | # partner type - always set |
950 | data.update({'partner_type': partner.partner_type, }) |
951 | |
952 | === modified file 'bin/addons/msf_order_date/order_dates_view.xml' |
953 | --- bin/addons/msf_order_date/order_dates_view.xml 2017-08-01 15:45:31 +0000 |
954 | +++ bin/addons/msf_order_date/order_dates_view.xml 2017-10-02 12:34:11 +0000 |
955 | @@ -36,20 +36,20 @@ |
956 | <group colspan="4" col="4"> |
957 | <separator colspan="4" string="Dates" /> |
958 | <group colspan="2" col="3"> |
959 | - <field name="delivery_requested_date" attrs="{'readonly': [('state', 'not in', ('draft', 'confirmed'))]}" |
960 | + <field name="delivery_requested_date" attrs="{'readonly': [('state', 'not in', ('draft', 'validated'))]}" |
961 | on_change="onchange_requested_date(partner_id,date_order,delivery_requested_date,est_transport_lead_time, order_type, context)" /> |
962 | <button colspan="1" name="update_date" string="Update Lines" type="object" context="{'field_name': 'requested', 'type': 'purchase.order'}" icon="gtk-indent" |
963 | - attrs="{'invisible': [('state', 'not in', ('draft', 'confirmed'))]}" /> |
964 | + attrs="{'invisible': [('state', 'not in', ('draft', 'validated'))]}" /> |
965 | </group> |
966 | <group colspan="2" col="3"> |
967 | - <field name="delivery_confirmed_date" attrs="{'readonly': [('state', 'not in', ('draft', 'confirmed'))]}" /> |
968 | + <field name="delivery_confirmed_date" attrs="{'readonly': [('state', 'not in', ('draft', 'validated'))]}" /> |
969 | <button colspan="1" name="update_date" string="Update Lines" type="object" context="{'field_name': 'confirmed', 'type': 'purchase.order'}" icon="gtk-indent" |
970 | - attrs="{'invisible': [('state', 'not in', ('draft', 'confirmed'))]}" /> |
971 | + attrs="{'invisible': [('state', 'not in', ('draft', 'validated'))]}" /> |
972 | </group> |
973 | <field name="transport_type" |
974 | on_change="onchange_transport_type(partner_id,transport_type,delivery_requested_date,context)" |
975 | - attrs="{'readonly': [('state', 'not in', ('draft', 'confirmed'))]}" /> |
976 | - <field name="est_transport_lead_time" attrs="{'readonly': [('state', 'not in', ('draft', 'confirmed'))]}" /> |
977 | + attrs="{'readonly': [('state', 'not in', ('draft', 'validated'))]}" /> |
978 | + <field name="est_transport_lead_time" attrs="{'readonly': [('state', 'not in', ('draft', 'validated'))]}" /> |
979 | <field name="ready_to_ship_date" attrs="{'readonly': ['|', ('shipped', '=', True), ('state', 'in', ['split', 'sourced'])], 'invisible': [('partner_type', '=', 'external')]}" /> |
980 | <field name="shipment_date" attrs="{'readonly': ['|', ('shipped', '=', True), ('state', 'in', ['split', 'sourced'])], 'invisible': [('partner_type', '=', 'external')]}" /> |
981 | <field name="arrival_date" attrs="{'readonly': ['|', ('shipped_rate', '!=', 0.0), ('state', '=', 'done')], 'invisible': [('internal_type', '!=', 'international')]}" /> |
982 | @@ -60,7 +60,7 @@ |
983 | <xpath expr="/form//field[@name='order_type']" position="replace"> |
984 | <field name="order_type" |
985 | on_change="onchange_internal_type(order_type, partner_id, categ, dest_partner_id, warehouse_id,delivery_requested_date)" |
986 | - attrs="{'readonly': ['|', ('push_fo', '=', True), ('state', 'not in', ['draft', 'confirmed'])]}" |
987 | + attrs="{'readonly': ['|', ('push_fo', '=', True), ('state', 'not in', ['draft', 'validated'])]}" |
988 | /> |
989 | </xpath> |
990 | |
991 | @@ -150,7 +150,7 @@ |
992 | |
993 | <xpath expr="/form/notebook//field[@name='order_line']/form/notebook//field[@name='delay']" position="replace"> |
994 | <field name="so_state_stored" invisible="True" /> |
995 | - <field name="date_planned" attrs="{'readonly': [('so_state_stored', 'not in', ['draft', 'validated'])]}" /> |
996 | + <field name="date_planned" attrs="{'readonly': [('state', 'not in', ['draft', 'validated'])]}" /> |
997 | <field name="confirmed_delivery_date" attrs="{'readonly': [('so_state_stored', 'in', ('cancel','done'))]}" /> |
998 | <field name="stock_take_date" /> |
999 | </xpath> |
1000 | |
1001 | === modified file 'bin/addons/msf_outgoing/msf_outgoing.py' |
1002 | --- bin/addons/msf_outgoing/msf_outgoing.py 2017-09-03 15:15:05 +0000 |
1003 | +++ bin/addons/msf_outgoing/msf_outgoing.py 2017-10-02 12:34:11 +0000 |
1004 | @@ -1663,6 +1663,10 @@ |
1005 | # UF-1617: set the flag to this packing object to indicate that the SHIP has been done, for synchronisation purpose |
1006 | cr.execute('update stock_picking set already_shipped=\'t\' where id=%s' % packing.id) |
1007 | |
1008 | + # closing FO lines: |
1009 | + for stock_move in packing.move_lines: |
1010 | + if stock_move.sale_line_id: |
1011 | + wf_service.trg_validate(uid, 'sale.order.line', stock_move.sale_line_id.id, 'done', cr) |
1012 | |
1013 | # Create automatically the invoice |
1014 | self.shipment_create_invoice(cr, uid, shipment.id, context=context) |
1015 | @@ -3412,6 +3416,8 @@ |
1016 | # Update the original move |
1017 | move_obj.write(cr, uid, [move.id], values, context=context) |
1018 | processed_moves.append(move.id) |
1019 | + if move.sale_line_id: |
1020 | + wf_service.trg_validate(uid, 'sale.order.line', move.sale_line_id.id, 'done', cr) |
1021 | |
1022 | if not len(move_data): |
1023 | pick_type = 'Internal picking' |
1024 | @@ -4967,11 +4973,11 @@ |
1025 | Confirm or check the procurement order associated to the stock move |
1026 | ''' |
1027 | pol_obj = self.pool.get('purchase.order.line') |
1028 | - proc_obj = self.pool.get('procurement.order') |
1029 | pick_obj = self.pool.get('stock.picking') |
1030 | sol_obj = self.pool.get('sale.order.line') |
1031 | uom_obj = self.pool.get('product.uom') |
1032 | solc_obj = self.pool.get('sale.order.line.cancel') |
1033 | + wf_service = netsvc.LocalService("workflow") |
1034 | |
1035 | if context is None: |
1036 | context = {} |
1037 | @@ -5021,8 +5027,10 @@ |
1038 | |
1039 | diff_qty = uom_obj._compute_qty(cr, uid, move.product_uom.id, move.product_qty, sol.product_uom.id) |
1040 | if move.has_to_be_resourced or move.picking_id.has_to_be_resourced: |
1041 | - sol_obj.add_resource_line(cr, uid, sol.id, False, diff_qty, context=context) |
1042 | - sol_obj.update_or_cancel_line(cr, uid, sol.id, diff_qty, context=context) |
1043 | + sol_obj.add_resource_line(cr, uid, sol.id, sol.order_id.id, diff_qty, context=context) |
1044 | + sol_obj.update_or_cancel_line(cr, uid, sol.id, diff_qty, resource=move.has_to_be_resourced,context=context) |
1045 | + signal = 'cancel_r' if move.has_to_be_resourced else 'cancel' |
1046 | + wf_service.trg_validate(uid, 'purchase.order.line', move.purchase_line_id.id, signal, cr) |
1047 | |
1048 | # Cancel the remaining OUT line |
1049 | if diff_qty < sol.product_uom_qty: |
1050 | @@ -5041,21 +5049,9 @@ |
1051 | diff_qty = uom_obj._compute_qty(cr, uid, move.product_uom.id, move.product_qty, move.sale_line_id.product_uom.id) |
1052 | if diff_qty: |
1053 | if move.has_to_be_resourced or move.picking_id.has_to_be_resourced: |
1054 | - sol_obj.add_resource_line(cr, uid, move.sale_line_id.id, False, diff_qty, context=context) |
1055 | + sol_obj.add_resource_line(cr, uid, move.sale_line_id.id, move.sale_line_id.order_id.id, diff_qty, context=context) |
1056 | if move.id not in context.get('not_resource_move', []): |
1057 | - sol_obj.update_or_cancel_line(cr, uid, move.sale_line_id.id, diff_qty, context=context) |
1058 | - if move.sale_line_id.procurement_id: |
1059 | - # Search OUT moves that have the same source and there are done |
1060 | - other_out_move_ids = self.search(cr, uid, [ |
1061 | - ('sale_line_id', '=', move.sale_line_id.id), |
1062 | - ('state', 'in', ['assigned', 'confirmed', 'done']), |
1063 | - ('id', '!=', move.id), |
1064 | - ], context=context) |
1065 | - if other_out_move_ids: |
1066 | - proc_obj.write(cr, uid, |
1067 | - [move.sale_line_id.procurement_id.id], |
1068 | - {'move_id': other_out_move_ids[0]}, |
1069 | - context=context) |
1070 | + sol_obj.update_or_cancel_line(cr, uid, move.sale_line_id.id, diff_qty, resource=move.has_to_be_resourced, context=context) |
1071 | |
1072 | self.action_done(cr, uid, move_to_done, context=context) |
1073 | |
1074 | @@ -5063,16 +5059,6 @@ |
1075 | ids = self.search(cr, uid, [('id', 'in', ids)]) |
1076 | res = super(stock_move, self).action_cancel(cr, uid, ids, context=context) |
1077 | |
1078 | - wf_service = netsvc.LocalService("workflow") |
1079 | - |
1080 | - proc_obj = self.pool.get('procurement.order') |
1081 | - proc_ids = proc_obj.search(cr, uid, [('move_id', 'in', ids)], context=context) |
1082 | - for proc in proc_obj.read(cr, uid, proc_ids, ['state'], context=context): |
1083 | - if proc['state'] == 'draft': |
1084 | - wf_service.trg_validate(uid, 'procurement.order', proc['id'], 'button_confirm', cr) |
1085 | - else: |
1086 | - wf_service.trg_validate(uid, 'procurement.order', proc['id'], 'button_check', cr) |
1087 | - |
1088 | for ptc in pick_obj.browse(cr, uid, list(pick_to_check), context=context): |
1089 | if ptc.subtype == 'picking' and ptc.state == 'draft' and not pick_obj.has_picking_ticket_in_progress(cr, uid, [ptc.id], context=context)[ptc.id] and all(m.state == 'cancel' or m.product_qty == 0.00 for m in ptc.move_lines): |
1090 | moves_to_done = self.search(cr, uid, [('picking_id', '=', ptc.id), ('product_qty', '=', 0.00), ('state', 'not in', ['done', 'cancel'])], context=context) |
1091 | |
1092 | === modified file 'bin/addons/msf_outgoing/msf_outgoing_view.xml' |
1093 | --- bin/addons/msf_outgoing/msf_outgoing_view.xml 2017-05-23 15:47:57 +0000 |
1094 | +++ bin/addons/msf_outgoing/msf_outgoing_view.xml 2017-10-02 12:34:11 +0000 |
1095 | @@ -353,7 +353,7 @@ |
1096 | <field name="has_draft_moves" invisible="1" /> |
1097 | <button name="action_confirm_moves" states="draft" string="Confirm" type="object" icon="gtk-apply" attrs="{'invisible': [('has_draft_moves', '=', False)]}"/> |
1098 | <button name="action_assign" states="draft,confirmed,assigned" string="Check Availability" type="object" icon="gtk-find" context="{'from_button': True}"/> |
1099 | - <button name="convert_to_standard" states="draft,assigned" string="Convert to Simple Out" type="object" icon="gtk-convert" context="{'from_button': True}" /> |
1100 | + <button name="convert_to_standard" states="draft" string="Convert to Simple Out" type="object" icon="gtk-convert" context="{'from_button': True}" /> |
1101 | <button name="create_picking" states="draft" string="Create Picking..." type="object" icon="gtk-add" help="Non available quantities will not be moved and will remain in the backorder document (unless you 'force availability' if you are sure goods are available)" context="{'from_button': True}" /> |
1102 | <button name="force_assign" states="confirmed" string="Force Availability" type="object" icon="gtk-jump-to" context="{'from_button': True}" /> |
1103 | <button name="validate_picking" states="assigned" string="Validate Picking..." type="object" icon="gtk-apply" context="{'from_button': True}" /> |
1104 | |
1105 | === modified file 'bin/addons/msf_processes/process/procurement_process.xml' |
1106 | --- bin/addons/msf_processes/process/procurement_process.xml 2012-06-07 15:50:33 +0000 |
1107 | +++ bin/addons/msf_processes/process/procurement_process.xml 2017-10-02 12:34:11 +0000 |
1108 | @@ -104,7 +104,7 @@ |
1109 | </record> |
1110 | |
1111 | <!-- transitions --> |
1112 | - |
1113 | +<!-- |
1114 | <record id="procurement.process_transition_draft_confirmed" model="process.transition"> |
1115 | <field eval="[(6,0,[])]" name="transition_ids"/> |
1116 | <field eval=""""Confirm Procurement Order"""" name="name"/> |
1117 | @@ -113,7 +113,7 @@ |
1118 | <field model="process.node" name="target_node_id" ref="procurement.process_node_procure_confirmed"/> |
1119 | <field eval="[(6,0,[ref('sale.trans_draft_router')])]" name="transition_ids"/> |
1120 | </record> |
1121 | - |
1122 | + |
1123 | <record id="procurement.process_transition_confirmed_exception" model="process.transition"> |
1124 | <field eval="[(6,0,[])]" name="transition_ids"/> |
1125 | <field eval=""""The Procurement Order goes in exception"""" name="name"/> |
1126 | @@ -176,7 +176,7 @@ |
1127 | <field model="process.node" name="target_node_id" ref="procurement.process_node_procure_po"/> |
1128 | <field eval="[(6,0,[ref('sale.trans_draft_router')])]" name="transition_ids"/> |
1129 | </record> |
1130 | - |
1131 | + |
1132 | <record id="procurement.process_transition_po_in" model="process.transition"> |
1133 | <field eval="[(6,0,[])]" name="transition_ids"/> |
1134 | <field eval=""""Incoming Products is created."""" name="name"/> |
1135 | @@ -185,7 +185,7 @@ |
1136 | <field model="process.node" name="target_node_id" ref="procurement.process_node_procure_in"/> |
1137 | <field eval="[(6,0,[ref('sale.trans_draft_router')])]" name="transition_ids"/> |
1138 | </record> |
1139 | - |
1140 | +--> |
1141 | <!-- Process process Service --> |
1142 | |
1143 | <record id="procurement.process_process_serviceproductprocess0" model="process.process"> |
1144 | |
1145 | === modified file 'bin/addons/msf_processes/process/purchase_process.xml' |
1146 | --- bin/addons/msf_processes/process/purchase_process.xml 2012-07-05 14:39:47 +0000 |
1147 | +++ bin/addons/msf_processes/process/purchase_process.xml 2017-10-02 12:34:11 +0000 |
1148 | @@ -171,7 +171,7 @@ |
1149 | <!-- |
1150 | Process Transition |
1151 | --> |
1152 | - |
1153 | +<!-- |
1154 | <record id="purchase.process_transition_confirmingpurchaseorder0" model="process.transition"> |
1155 | <field eval="[(6,0,[])]" name="transition_ids"/> |
1156 | <field eval=""""Confirmation"""" name="name"/> |
1157 | @@ -180,7 +180,7 @@ |
1158 | <field model="process.node" name="source_node_id" ref="purchase.process_node_draftpurchaseorder0"/> |
1159 | <field eval="[(6,0,[ref('purchase.trans_draft_confirmed')])]" name="transition_ids"/> |
1160 | </record> |
1161 | - |
1162 | +--> |
1163 | <record id="purchase.process_transition_confirmingpurchaseorder1" model="process.transition"> |
1164 | <field eval="[(6,0,[])]" name="transition_ids"/> |
1165 | <field eval=""""Confirmation"""" name="name"/> |
1166 | @@ -265,7 +265,7 @@ |
1167 | <!-- |
1168 | Process Action |
1169 | --> |
1170 | - |
1171 | +<!-- |
1172 | <record id="purchase.process_transition_action_confirmpurchaseorder0" model="process.transition.action"> |
1173 | <field eval=""""wkf_confirm_order"""" name="action"/> |
1174 | <field eval=""""object"""" name="state"/> |
1175 | @@ -293,7 +293,7 @@ |
1176 | <field eval=""""Cancel"""" name="name"/> |
1177 | <field name="transition_id" ref="purchase.process_transition_approvingpurchaseorder0"/> |
1178 | </record> |
1179 | -<!-- |
1180 | + |
1181 | <record id="purchase.process_transition_action_invoicefrompurchaseorder0" model="process.transition.action"> |
1182 | <field eval=""""action_invoice_create"""" name="action"/> |
1183 | <field eval=""""object"""" name="state"/> |
1184 | |
1185 | === modified file 'bin/addons/msf_processes/process/sale_process.xml' |
1186 | --- bin/addons/msf_processes/process/sale_process.xml 2012-06-07 15:50:33 +0000 |
1187 | +++ bin/addons/msf_processes/process/sale_process.xml 2017-10-02 12:34:11 +0000 |
1188 | @@ -210,7 +210,7 @@ |
1189 | <!-- |
1190 | Process Transition |
1191 | --> |
1192 | - |
1193 | +<!-- |
1194 | <record id="sale.process_transition_validatequotation0" model="process.transition"> |
1195 | <field eval="[(6,0,[])]" name="transition_ids"/> |
1196 | <field eval=""""Confirm Field Order"""" name="name"/> |
1197 | @@ -237,7 +237,7 @@ |
1198 | <field model="process.node" name="target_node_id" ref="sale.process_node_saleorder_done"/> |
1199 | <field eval="[(6,0,[ref('sale.trans_draft_router')])]" name="transition_ids"/> |
1200 | </record> |
1201 | - |
1202 | +--> |
1203 | <record id="sale.process_transition_saleprocurement0" model="process.transition"> |
1204 | <field eval="[(6,0,[])]" name="transition_ids"/> |
1205 | <field eval=""""Create Procurement Order"""" name="name"/> |
1206 | @@ -308,7 +308,7 @@ |
1207 | <!-- |
1208 | Process Action |
1209 | --> |
1210 | - |
1211 | +<!-- |
1212 | <record id="sale.process_transition_action_confirm0" model="process.transition.action"> |
1213 | <field eval=""""action_wait"""" name="action"/> |
1214 | <field eval=""""object"""" name="state"/> |
1215 | @@ -364,7 +364,7 @@ |
1216 | <field eval=""""Cancel"""" name="name"/> |
1217 | <field name="transition_id" ref="sale.process_transition_deliver0"/> |
1218 | </record> |
1219 | -<!-- |
1220 | + |
1221 | <record id="sale.process_transition_action_createinvoice0" model="process.transition.action"> |
1222 | <field eval=""""action_invoice_create"""" name="action"/> |
1223 | <field eval=""""object"""" name="state"/> |
1224 | |
1225 | === modified file 'bin/addons/msf_profile/__openerp__.py' |
1226 | --- bin/addons/msf_profile/__openerp__.py 2017-08-21 10:09:52 +0000 |
1227 | +++ bin/addons/msf_profile/__openerp__.py 2017-10-02 12:34:11 +0000 |
1228 | @@ -40,7 +40,7 @@ |
1229 | "account_period_closing_level", |
1230 | # As register_accounting has account_override and purchase_override dependancies, no need to add them after that |
1231 | #"purchase_override", |
1232 | - "sale_override", |
1233 | + "sale", |
1234 | "stock_override", |
1235 | "msf_order_date", |
1236 | "purchase_compare_rfq", |
1237 | @@ -116,7 +116,6 @@ |
1238 | "update_xml": [ |
1239 | "security/ir.model.access.csv", |
1240 | "report.xml", |
1241 | - "purchase_double_validation_workflow.xml", |
1242 | "usability.xml", |
1243 | "user_access_configurator_view.xml", |
1244 | "unifield_version_view.xml", |
1245 | |
1246 | === modified file 'bin/addons/msf_profile/i18n/fr_MF.po' |
1247 | --- bin/addons/msf_profile/i18n/fr_MF.po 2017-09-18 12:35:40 +0000 |
1248 | +++ bin/addons/msf_profile/i18n/fr_MF.po 2017-10-02 12:34:11 +0000 |
1249 | @@ -98454,7 +98454,7 @@ |
1250 | "- 'Catégorie Bilan/Cte de Résultat' ne doit pas être vide." |
1251 | |
1252 | #. module: msf_doc_import |
1253 | -#: code:addons/msf_doc_import/wizard/wizard_import_invoice_line.py:168 |
1254 | +#: code:addons/msf_doc_import/wizard/wizard_import_invoice_line.py:184 |
1255 | #, python-format |
1256 | msgid "\n" |
1257 | "- 'Account Type' should be in ('expense', 'income', 'receivables')." |
1258 | |
1259 | === removed file 'bin/addons/msf_profile/purchase_double_validation_workflow.xml' |
1260 | --- bin/addons/msf_profile/purchase_double_validation_workflow.xml 2012-06-27 15:03:40 +0000 |
1261 | +++ bin/addons/msf_profile/purchase_double_validation_workflow.xml 1970-01-01 00:00:00 +0000 |
1262 | @@ -1,18 +0,0 @@ |
1263 | -<?xml version="1.0" encoding="utf-8"?> |
1264 | -<openerp> |
1265 | - <data> |
1266 | - |
1267 | - <record id="purchase.trans_confirmed_router" model="workflow.transition"> |
1268 | - <field name="condition">amount_total >= 0</field> |
1269 | - <field name="signal">purchase_approve</field> |
1270 | - <field name="group_id" ref="purchase.group_purchase_manager"/> |
1271 | - </record> |
1272 | - |
1273 | - <record id="purchase_double_validation.trans_waiting_confirmed" model="workflow.transition"> |
1274 | - <field name="act_from" ref="purchase.act_confirmed"/> |
1275 | - <field name="act_to" ref="purchase.act_router"/> |
1276 | - <field name="condition">amount_total < 0</field> |
1277 | - </record> |
1278 | - |
1279 | - </data> |
1280 | -</openerp> |
1281 | |
1282 | === modified file 'bin/addons/msf_profile/test/user_rights_test_files/user_rights_01_10-lines-removed_all-groups.xml' |
1283 | --- bin/addons/msf_profile/test/user_rights_test_files/user_rights_01_10-lines-removed_all-groups.xml 2016-11-14 11:27:07 +0000 |
1284 | +++ bin/addons/msf_profile/test/user_rights_test_files/user_rights_01_10-lines-removed_all-groups.xml 2017-10-02 12:34:11 +0000 |
1285 | @@ -2158,7 +2158,7 @@ |
1286 | <Cell><Data ss:Type="String">YES</Data></Cell> |
1287 | </Row> |
1288 | <Row ss:AutoFitHeight="0"> |
1289 | - <Cell><Data ss:Type="String">sale_override</Data></Cell> |
1290 | + <Cell><Data ss:Type="String">sale</Data></Cell> |
1291 | <Cell><Data ss:Type="String">menu_localisation</Data></Cell> |
1292 | <Cell><Data ss:Type="Number">0</Data></Cell> |
1293 | <Cell><Data ss:Type="String">Localisation</Data></Cell> |
1294 | @@ -2173,7 +2173,7 @@ |
1295 | <Cell><Data ss:Type="String">NO</Data></Cell> |
1296 | </Row> |
1297 | <Row ss:AutoFitHeight="0"> |
1298 | - <Cell><Data ss:Type="String">sale_override</Data></Cell> |
1299 | + <Cell><Data ss:Type="String">sale</Data></Cell> |
1300 | <Cell><Data ss:Type="String">menu_country_partner</Data></Cell> |
1301 | <Cell><Data ss:Type="String">++</Data></Cell> |
1302 | <Cell><Data ss:Type="String">Countries</Data></Cell> |
1303 | @@ -2188,7 +2188,7 @@ |
1304 | <Cell><Data ss:Type="String">NO</Data></Cell> |
1305 | </Row> |
1306 | <Row ss:AutoFitHeight="0"> |
1307 | - <Cell><Data ss:Type="String">sale_override</Data></Cell> |
1308 | + <Cell><Data ss:Type="String">sale</Data></Cell> |
1309 | <Cell><Data ss:Type="String">menu_country_state_partner</Data></Cell> |
1310 | <Cell><Data ss:Type="String">++</Data></Cell> |
1311 | <Cell><Data ss:Type="String">Fed. States</Data></Cell> |
1312 | |
1313 | === modified file 'bin/addons/msf_profile/test/user_rights_test_files/user_rights_01_10-lines-removed_no-cashier_no-productManager.xml' |
1314 | --- bin/addons/msf_profile/test/user_rights_test_files/user_rights_01_10-lines-removed_no-cashier_no-productManager.xml 2016-11-14 11:27:07 +0000 |
1315 | +++ bin/addons/msf_profile/test/user_rights_test_files/user_rights_01_10-lines-removed_no-cashier_no-productManager.xml 2017-10-02 12:34:11 +0000 |
1316 | @@ -2002,7 +2002,7 @@ |
1317 | <Cell><Data ss:Type="String">YES</Data></Cell> |
1318 | </Row> |
1319 | <Row ss:AutoFitHeight="0"> |
1320 | - <Cell><Data ss:Type="String">sale_override</Data></Cell> |
1321 | + <Cell><Data ss:Type="String">sale</Data></Cell> |
1322 | <Cell><Data ss:Type="String">menu_localisation</Data></Cell> |
1323 | <Cell><Data ss:Type="Number">0</Data></Cell> |
1324 | <Cell><Data ss:Type="String">Localisation</Data></Cell> |
1325 | @@ -2016,7 +2016,7 @@ |
1326 | <Cell><Data ss:Type="String">NO</Data></Cell> |
1327 | </Row> |
1328 | <Row ss:AutoFitHeight="0"> |
1329 | - <Cell><Data ss:Type="String">sale_override</Data></Cell> |
1330 | + <Cell><Data ss:Type="String">sale</Data></Cell> |
1331 | <Cell><Data ss:Type="String">menu_country_partner</Data></Cell> |
1332 | <Cell><Data ss:Type="String">++</Data></Cell> |
1333 | <Cell><Data ss:Type="String">Countries</Data></Cell> |
1334 | @@ -2030,7 +2030,7 @@ |
1335 | <Cell><Data ss:Type="String">NO</Data></Cell> |
1336 | </Row> |
1337 | <Row ss:AutoFitHeight="0"> |
1338 | - <Cell><Data ss:Type="String">sale_override</Data></Cell> |
1339 | + <Cell><Data ss:Type="String">sale</Data></Cell> |
1340 | <Cell><Data ss:Type="String">menu_country_state_partner</Data></Cell> |
1341 | <Cell><Data ss:Type="String">++</Data></Cell> |
1342 | <Cell><Data ss:Type="String">Fed. States</Data></Cell> |
1343 | |
1344 | === modified file 'bin/addons/msf_profile/test/user_rights_test_files/user_rights_01_all-lines_all-groups.xml' |
1345 | --- bin/addons/msf_profile/test/user_rights_test_files/user_rights_01_all-lines_all-groups.xml 2016-11-14 11:27:07 +0000 |
1346 | +++ bin/addons/msf_profile/test/user_rights_test_files/user_rights_01_all-lines_all-groups.xml 2017-10-02 12:34:11 +0000 |
1347 | @@ -2297,7 +2297,7 @@ |
1348 | <Cell><Data ss:Type="String">YES</Data></Cell> |
1349 | </Row> |
1350 | <Row> |
1351 | - <Cell><Data ss:Type="String">sale_override</Data></Cell> |
1352 | + <Cell><Data ss:Type="String">sale</Data></Cell> |
1353 | <Cell><Data ss:Type="String">menu_localisation</Data></Cell> |
1354 | <Cell><Data ss:Type="Number">0</Data></Cell> |
1355 | <Cell><Data ss:Type="String">Localisation</Data></Cell> |
1356 | @@ -2312,7 +2312,7 @@ |
1357 | <Cell><Data ss:Type="String">NO</Data></Cell> |
1358 | </Row> |
1359 | <Row> |
1360 | - <Cell><Data ss:Type="String">sale_override</Data></Cell> |
1361 | + <Cell><Data ss:Type="String">sale</Data></Cell> |
1362 | <Cell><Data ss:Type="String">menu_country_partner</Data></Cell> |
1363 | <Cell><Data ss:Type="String">++</Data></Cell> |
1364 | <Cell><Data ss:Type="String">Countries</Data></Cell> |
1365 | @@ -2327,7 +2327,7 @@ |
1366 | <Cell><Data ss:Type="String">NO</Data></Cell> |
1367 | </Row> |
1368 | <Row> |
1369 | - <Cell><Data ss:Type="String">sale_override</Data></Cell> |
1370 | + <Cell><Data ss:Type="String">sale</Data></Cell> |
1371 | <Cell><Data ss:Type="String">menu_country_state_partner</Data></Cell> |
1372 | <Cell><Data ss:Type="String">++</Data></Cell> |
1373 | <Cell><Data ss:Type="String">Fed. States</Data></Cell> |
1374 | |
1375 | === modified file 'bin/addons/msf_profile/test/user_rights_test_files/user_rights_01_all-lines_all-groups_misformed_no-header.xml' |
1376 | --- bin/addons/msf_profile/test/user_rights_test_files/user_rights_01_all-lines_all-groups_misformed_no-header.xml 2016-11-14 11:27:07 +0000 |
1377 | +++ bin/addons/msf_profile/test/user_rights_test_files/user_rights_01_all-lines_all-groups_misformed_no-header.xml 2017-10-02 12:34:11 +0000 |
1378 | @@ -2273,7 +2273,7 @@ |
1379 | <Cell><Data ss:Type="String">YES</Data></Cell> |
1380 | </Row> |
1381 | <Row ss:AutoFitHeight="0"> |
1382 | - <Cell><Data ss:Type="String">sale_override</Data></Cell> |
1383 | + <Cell><Data ss:Type="String">sale</Data></Cell> |
1384 | <Cell><Data ss:Type="String">menu_localisation</Data></Cell> |
1385 | <Cell><Data ss:Type="Number">0</Data></Cell> |
1386 | <Cell><Data ss:Type="String">Localisation</Data></Cell> |
1387 | @@ -2288,7 +2288,7 @@ |
1388 | <Cell><Data ss:Type="String">NO</Data></Cell> |
1389 | </Row> |
1390 | <Row ss:AutoFitHeight="0"> |
1391 | - <Cell><Data ss:Type="String">sale_override</Data></Cell> |
1392 | + <Cell><Data ss:Type="String">sale</Data></Cell> |
1393 | <Cell><Data ss:Type="String">menu_country_partner</Data></Cell> |
1394 | <Cell><Data ss:Type="String">++</Data></Cell> |
1395 | <Cell><Data ss:Type="String">Countries</Data></Cell> |
1396 | @@ -2303,7 +2303,7 @@ |
1397 | <Cell><Data ss:Type="String">NO</Data></Cell> |
1398 | </Row> |
1399 | <Row ss:AutoFitHeight="0"> |
1400 | - <Cell><Data ss:Type="String">sale_override</Data></Cell> |
1401 | + <Cell><Data ss:Type="String">sale</Data></Cell> |
1402 | <Cell><Data ss:Type="String">menu_country_state_partner</Data></Cell> |
1403 | <Cell><Data ss:Type="String">++</Data></Cell> |
1404 | <Cell><Data ss:Type="String">Fed. States</Data></Cell> |
1405 | |
1406 | === modified file 'bin/addons/msf_profile/test/user_rights_test_files/user_rights_01_all-lines_no-cashier_no-productManager.xml' |
1407 | --- bin/addons/msf_profile/test/user_rights_test_files/user_rights_01_all-lines_no-cashier_no-productManager.xml 2016-11-14 11:27:07 +0000 |
1408 | +++ bin/addons/msf_profile/test/user_rights_test_files/user_rights_01_all-lines_no-cashier_no-productManager.xml 2017-10-02 12:34:11 +0000 |
1409 | @@ -2131,7 +2131,7 @@ |
1410 | <Cell><Data ss:Type="String">YES</Data></Cell> |
1411 | </Row> |
1412 | <Row ss:AutoFitHeight="0"> |
1413 | - <Cell><Data ss:Type="String">sale_override</Data></Cell> |
1414 | + <Cell><Data ss:Type="String">sale</Data></Cell> |
1415 | <Cell><Data ss:Type="String">menu_localisation</Data></Cell> |
1416 | <Cell><Data ss:Type="Number">0</Data></Cell> |
1417 | <Cell><Data ss:Type="String">Localisation</Data></Cell> |
1418 | @@ -2145,7 +2145,7 @@ |
1419 | <Cell><Data ss:Type="String">NO</Data></Cell> |
1420 | </Row> |
1421 | <Row ss:AutoFitHeight="0"> |
1422 | - <Cell><Data ss:Type="String">sale_override</Data></Cell> |
1423 | + <Cell><Data ss:Type="String">sale</Data></Cell> |
1424 | <Cell><Data ss:Type="String">menu_country_partner</Data></Cell> |
1425 | <Cell><Data ss:Type="String">++</Data></Cell> |
1426 | <Cell><Data ss:Type="String">Countries</Data></Cell> |
1427 | @@ -2159,7 +2159,7 @@ |
1428 | <Cell><Data ss:Type="String">NO</Data></Cell> |
1429 | </Row> |
1430 | <Row ss:AutoFitHeight="0"> |
1431 | - <Cell><Data ss:Type="String">sale_override</Data></Cell> |
1432 | + <Cell><Data ss:Type="String">sale</Data></Cell> |
1433 | <Cell><Data ss:Type="String">menu_country_state_partner</Data></Cell> |
1434 | <Cell><Data ss:Type="String">++</Data></Cell> |
1435 | <Cell><Data ss:Type="String">Fed. States</Data></Cell> |
1436 | |
1437 | === modified file 'bin/addons/msf_profile/test/user_rights_test_files/user_rights_01_all-lines_no-groups.xml' |
1438 | --- bin/addons/msf_profile/test/user_rights_test_files/user_rights_01_all-lines_no-groups.xml 2016-11-14 11:27:07 +0000 |
1439 | +++ bin/addons/msf_profile/test/user_rights_test_files/user_rights_01_all-lines_no-groups.xml 2017-10-02 12:34:11 +0000 |
1440 | @@ -930,19 +930,19 @@ |
1441 | <Cell><Data ss:Type="String">Reconfigure</Data></Cell> |
1442 | </Row> |
1443 | <Row ss:AutoFitHeight="0"> |
1444 | - <Cell><Data ss:Type="String">sale_override</Data></Cell> |
1445 | + <Cell><Data ss:Type="String">sale</Data></Cell> |
1446 | <Cell><Data ss:Type="String">menu_localisation</Data></Cell> |
1447 | <Cell><Data ss:Type="Number">0</Data></Cell> |
1448 | <Cell><Data ss:Type="String">Localisation</Data></Cell> |
1449 | </Row> |
1450 | <Row ss:AutoFitHeight="0"> |
1451 | - <Cell><Data ss:Type="String">sale_override</Data></Cell> |
1452 | + <Cell><Data ss:Type="String">sale</Data></Cell> |
1453 | <Cell><Data ss:Type="String">menu_country_partner</Data></Cell> |
1454 | <Cell><Data ss:Type="String">++</Data></Cell> |
1455 | <Cell><Data ss:Type="String">Countries</Data></Cell> |
1456 | </Row> |
1457 | <Row ss:AutoFitHeight="0"> |
1458 | - <Cell><Data ss:Type="String">sale_override</Data></Cell> |
1459 | + <Cell><Data ss:Type="String">sale</Data></Cell> |
1460 | <Cell><Data ss:Type="String">menu_country_state_partner</Data></Cell> |
1461 | <Cell><Data ss:Type="String">++</Data></Cell> |
1462 | <Cell><Data ss:Type="String">Fed. States</Data></Cell> |
1463 | |
1464 | === modified file 'bin/addons/msf_profile/test/user_rights_test_files/user_rights_01_original.csv' |
1465 | --- bin/addons/msf_profile/test/user_rights_test_files/user_rights_01_original.csv 2013-03-07 16:41:45 +0000 |
1466 | +++ bin/addons/msf_profile/test/user_rights_test_files/user_rights_01_original.csv 2017-10-02 12:34:11 +0000 |
1467 | @@ -148,9 +148,9 @@ |
1468 | base;menu_ir_property_form_all;+++;Configuration Parameters;NO;NO;NO;NO;NO;NO;NO;NO;NO;YES;YES;NO;NO;NO;NO;NO;NO;NO |
1469 | msf_instance;menu_action_msf_instance_tree;++;Proprietary Instances;NO;NO;NO;NO;NO;NO;NO;NO;NO;YES;YES;NO;NO;NO;NO;NO;NO;NO |
1470 | base;menu_view_base_module_configuration;++;Reconfigure;NO;NO;NO;NO;NO;NO;NO;NO;NO;YES;YES;NO;NO;NO;NO;NO;NO;YES |
1471 | -sale_override;menu_localisation;0;Localisation;;;;;;;;;;YES;YES;NO;NO;NO;NO;NO;NO;NO |
1472 | -sale_override;menu_country_partner;++;Countries;;;;;;;;;;YES;YES;NO;NO;NO;NO;NO;NO;NO |
1473 | -sale_override;menu_country_state_partner;++;Fed. States;;;;;;;;;;YES;YES;NO;NO;NO;NO;NO;NO;NO |
1474 | +sale;menu_localisation;0;Localisation;;;;;;;;;;YES;YES;NO;NO;NO;NO;NO;NO;NO |
1475 | +sale;menu_country_partner;++;Countries;;;;;;;;;;YES;YES;NO;NO;NO;NO;NO;NO;NO |
1476 | +sale;menu_country_state_partner;++;Fed. States;;;;;;;;;;YES;YES;NO;NO;NO;NO;NO;NO;NO |
1477 | base;menu_custom;0;Customization;NO;NO;NO;NO;NO;NO;NO;NO;NO;YES;YES;NO;NO;NO;NO;NO;NO;NO |
1478 | base;next_id_2;++;User Interface;NO;NO;NO;NO;NO;NO;NO;NO;NO;YES;YES;NO;NO;NO;NO;NO;NO;NO |
1479 | base;menu_grant_menu_access;+++;Menu Items;NO;NO;NO;NO;NO;NO;NO;NO;NO;YES;YES;NO;NO;NO;NO;NO;NO;NO |
1480 | |
1481 | === modified file 'bin/addons/msf_sync_data_server/data/sync_server.message_rule.csv' |
1482 | --- bin/addons/msf_sync_data_server/data/sync_server.message_rule.csv 2017-08-03 15:16:40 +0000 |
1483 | +++ bin/addons/msf_sync_data_server/data/sync_server.message_rule.csv 2017-10-02 12:34:11 +0000 |
1484 | @@ -1,18 +1,15 @@ |
1485 | id,active,applies_to_type,arguments,domain,destination_name,type_id,remote_call,model_id,name,sequence_number,status |
1486 | msf_sync_data_server.resourcing_lines,TRUE,TRUE,"['sync_order_line_db_id', 'partner_id', 'resource_ok', 'resource_sync_line_db_id', 'partner_type']","[('partner_type','!=','external'), ('partner_id', '!=', False)]",partner_id,MISSION,sale.order.line.cancel.create_line,sale.order.line.cancel,Resourcing lines,1,Valid |
1487 | -msf_sync_data_server.po_creates_fo,TRUE,TRUE,"['name', 'analytic_distribution_id/id', 'delivery_requested_date','details','notes', 'origin', 'categ', 'order_type', 'priority', 'loan_duration', 'is_a_counterpart', 'sourced_references', 'stock_take_date', 'order_line/product_id/id', 'order_line/product_id/name','order_line/id', 'order_line/name', 'order_line/product_qty', 'order_line/product_uom', 'order_line/price_unit', 'order_line/analytic_distribution_id/id','order_line/comment','order_line/have_analytic_distribution_from_header','order_line/line_number', 'order_line/nomen_manda_0/id','order_line/nomen_manda_1/id','order_line/nomen_manda_2/id','order_line/nomen_manda_3/id', 'order_line/sync_order_line_db_id', 'order_line/nomenclature_description','order_line/notes','order_line/default_name','order_line/default_code','order_line/is_line_split','order_line/date_planned', 'order_line/stock_take_date']","['&','&','&',('partner_type','!=','external'),('state','in',['confirmed']), ('split_po','!=','True'),('push_fo','!=','True')]",partner_id,MISSION,sale.order.create_so,purchase.order,PO creates FO,2,Valid |
1488 | -msf_sync_data_server.split_po_lines_from_splitted_fo_lines,TRUE,TRUE,"['partner_id','old_sync_order_line_db_id','new_sync_order_line_db_id','new_line_qty','old_line_qty']","[]",partner_id,MISSION,purchase.order.line.to.split.create_from_sync_message,sync.sale.order.line.split,Split PO lines from splitted FO lines,3,Valid |
1489 | -msf_sync_data_server.validated_fo_updates_po,TRUE,TRUE,"['name','state','analytic_distribution_id/id', 'original_so_id_sale_order','categ', 'order_type', 'priority', 'loan_duration','delivery_confirmed_date','est_transport_lead_time', 'transport_type', 'ready_to_ship_date', 'details', 'note','client_order_ref', 'stock_take_date', 'order_line/product_id/id', 'order_line/product_id/name','order_line/id', 'order_line/name', 'order_line/product_uom_qty', 'order_line/product_uom', 'order_line/price_unit', 'order_line/analytic_distribution_id/id','order_line/comment','order_line/have_analytic_distribution_from_header','order_line/line_number', 'order_line/nomen_manda_0/id','order_line/nomen_manda_1/id','order_line/nomen_manda_2/id','order_line/nomen_manda_3/id', 'order_line/sync_order_line_db_id', 'order_line/nomenclature_description','order_line/notes','order_line/default_name','order_line/default_code','order_line/date_planned','order_line/is_line_split', 'order_line/confirmed_delivery_date', 'order_line/cancel_split_ok', 'order_line/stock_take_date']","['&','&','&',('partner_type','!=','external'),('state','in',['validated', 'done']),('original_so_id_sale_order','=',''), ('client_order_ref','!=',False)]",partner_id,MISSION,purchase.order.validated_fo_update_original_po,sale.order,Validated FO updates PO,4,Valid |
1490 | -msf_sync_data_server.normal_fo_creates_po,TRUE,TRUE,"['name','state','analytic_distribution_id/id','parent_order_name','delivery_confirmed_date','est_transport_lead_time', 'categ', 'order_type', 'priority', 'loan_duration','transport_type', 'ready_to_ship_date', 'details', 'note','client_order_ref', 'stock_take_date', 'order_line/product_id/id', 'order_line/product_id/name','order_line/id', 'order_line/name', 'order_line/product_uom_qty', 'order_line/product_uom', 'order_line/price_unit', 'order_line/analytic_distribution_id/id','order_line/comment','order_line/have_analytic_distribution_from_header','order_line/line_number', 'order_line/nomen_manda_0/id','order_line/nomen_manda_1/id','order_line/nomen_manda_2/id','order_line/nomen_manda_3/id', 'order_line/sync_order_line_db_id', 'order_line/nomenclature_description','order_line/notes','order_line/default_name','order_line/default_code','order_line/date_planned', 'order_line/confirmed_delivery_date', 'order_line/stock_take_date']","['&','&','&',('partner_type','!=','external'),('state','in',['validated','done']),('client_order_ref','=',False),('split_type_sale_order','=','original_sale_order')]",partner_id,MISSION,purchase.order.normal_fo_create_po,sale.order,Normal FO creates PO,5,Valid |
1491 | -msf_sync_data_server.split_fo_creates_split_po,TRUE,TRUE,"['name','state','analytic_distribution_id/id', 'delivery_confirmed_date','categ', 'order_type', 'priority', 'loan_duration','est_transport_lead_time', 'transport_type', 'ready_to_ship_date', 'details', 'note','client_order_ref', 'stock_take_date', 'order_line/product_id/id', 'order_line/product_id/name','order_line/id', 'order_line/is_line_split','order_line/name', 'order_line/product_uom_qty', 'order_line/product_uom', 'order_line/price_unit', 'order_line/analytic_distribution_id/id','order_line/comment','order_line/have_analytic_distribution_from_header','order_line/line_number', 'order_line/nomen_manda_0/id','order_line/nomen_manda_1/id','order_line/nomen_manda_2/id','order_line/nomen_manda_3/id', 'order_line/sync_order_line_db_id', 'order_line/nomenclature_description','order_line/notes','order_line/default_name','order_line/default_code','order_line/date_planned', 'order_line/confirmed_delivery_date', 'order_line/source_sync_line_id', 'order_line/stock_take_date']","['&',('partner_type','!=','external'),('original_so_id_sale_order','!=','False')]",partner_id,MISSION,purchase.order.create_split_po,sale.order,Split FO creates Split PO,6,Valid |
1492 | -msf_sync_data_server.split_fo_updates_split_po,TRUE,TRUE,"['name', 'state', 'client_order_ref','sync_date','analytic_distribution_id/id','categ', 'order_type', 'priority', 'loan_duration', 'delivery_confirmed_date','est_transport_lead_time', 'transport_type', 'note','original_so_id_sale_order', 'ready_to_ship_date', 'stock_take_date', 'order_line/product_id/id', 'order_line/product_id/name','order_line/id', 'order_line/name', 'order_line/is_line_split','order_line/product_uom_qty', 'order_line/product_uom', 'order_line/price_unit', 'order_line/analytic_distribution_id/id','order_line/comment','order_line/have_analytic_distribution_from_header','order_line/line_number', 'order_line/nomen_manda_0/id','order_line/nomen_manda_1/id','order_line/nomen_manda_2/id','order_line/nomen_manda_3/id', 'order_line/sync_order_line_db_id', 'order_line/nomenclature_description','order_line/notes','order_line/default_name','order_line/default_code', 'order_line/confirmed_delivery_date', 'order_line/source_sync_line_id', 'order_line/sync_sourced_origin', 'order_line/stock_take_date']","['&','&',('partner_type','!=','external'),('state','in',['manual','progress','shipping_except','invoice_except','done']),('original_so_id_sale_order','!=','False')]",partner_id,MISSION,purchase.order.update_split_po,sale.order,Split FO updates split PO,7,Valid |
1493 | +msf_sync_data_server.po_creates_fo,TRUE,TRUE,"['name', 'analytic_distribution_id/id', 'delivery_requested_date','details','notes', 'origin', 'categ', 'order_type', 'priority', 'loan_duration', 'is_a_counterpart', 'sourced_references', 'stock_take_date']","['&','&','&',('partner_type','not in',['external','esc']),('state','in',['validated']), ('split_po','!=','True'),('push_fo','!=','True')]",partner_id,MISSION,sale.order.create_so,purchase.order,PO creates FO,2,Valid |
1494 | +msf_sync_data_server.normal_fo_creates_po,TRUE,TRUE,"['name','state','analytic_distribution_id/id','parent_order_name','delivery_confirmed_date','est_transport_lead_time', 'categ', 'order_type', 'priority', 'loan_duration','transport_type', 'ready_to_ship_date', 'details', 'note','client_order_ref', 'stock_take_date', 'order_line/product_id/id', 'order_line/product_id/name','order_line/id', 'order_line/name', 'order_line/product_uom_qty', 'order_line/product_uom', 'order_line/price_unit', 'order_line/analytic_distribution_id/id','order_line/comment','order_line/have_analytic_distribution_from_header','order_line/line_number', 'order_line/nomen_manda_0/id','order_line/nomen_manda_1/id','order_line/nomen_manda_2/id','order_line/nomen_manda_3/id', 'order_line/sync_order_line_db_id', 'order_line/nomenclature_description','order_line/notes','order_line/default_name','order_line/default_code','order_line/date_planned', 'order_line/confirmed_delivery_date', 'order_line/stock_take_date']","[('partner_type','!=','external'),('state','not in',['draft']),('client_order_ref','=',False)]",partner_id,MISSION,purchase.order.normal_fo_create_po,sale.order,Normal FO creates PO,5,Valid |
1495 | msf_sync_data_server.po_updates_so_ref,TRUE,TRUE,"['name','state','partner_ref']","['&','&','&',('partner_type','!=','external'),('state','in',['confirmed','sourced','split', 'approved']),('partner_ref','!=',False),'!',('partner_ref', 'like', 'invalid_by_recovery')]",partner_id,MISSION,sale.order.update_sub_so_ref,purchase.order,PO updates SO ref,8,Valid |
1496 | msf_sync_data_server.fo_updates_po_ref,TRUE,TRUE,"['name','state','client_order_ref']","['&','&','&',('partner_type','!=','external'),('client_order_ref','!=',False),('split_type_sale_order','=','original_sale_order'),'!',('client_order_ref', 'like', 'invalid_by_recovery')]",partner_id,MISSION,purchase.order.update_fo_ref,sale.order,FO updates PO ref,9,Valid |
1497 | msf_sync_data_server.update_in_ref,TRUE,TRUE,"['name','shipment_ref']","['&',('shipment_ref','!=',False),'!',('shipment_ref', 'like', 'invalid_by_recovery')]",partner_id,MISSION,stock.picking.update_in_ref,stock.picking,IN updates ref to OUT SHIP,10,Valid |
1498 | -msf_sync_data_server.canceled_fo_cancels_po,TRUE,TRUE,"['name','state', 'client_order_ref']","[('state', '=', 'cancel'), ('client_order_ref', '!=', '')]",partner_id,MISSION,purchase.order.canceled_fo_cancel_po,sale.order,Canceled FO cancels PO,18,Valid |
1499 | +msf_sync_data_server.pol_create_sol,TRUE,TRUE,"['sync_local_id', 'order_id/name','product_id/id', 'product_id/name', 'name', 'state', 'product_qty', 'product_uom', 'price_unit', 'analytic_distribution_id/id','comment','have_analytic_distribution_from_header','line_number', 'nomen_manda_0/id','nomen_manda_1/id','nomen_manda_2/id','nomen_manda_3/id', 'nomenclature_description','notes','default_name','default_code','is_line_split','date_planned', 'stock_take_date']","[('sync_linked_sol', '=', False), ('order_id.partner_type', 'not in',['external','esc']), ('state', 'in', ['validated', 'confirmed', 'done']), ('order_id.state', 'not in', ['draft', 'cancel'])]",partner_id,MISSION,sale.order.line.create_so_line,purchase.order.line,PO line creates FO line,11,Valid |
1500 | +msf_sync_data_server.sol_updates_pol,TRUE,TRUE,"['resourced_original_line/id', 'resourced_original_remote_line','sync_sourced_origin', 'sync_local_id', 'sync_linked_pol', 'order_id/name', 'product_id/id', 'product_id/name', 'name', 'state','product_uom_qty', 'product_uom', 'price_unit', 'analytic_distribution_id/id','comment','have_analytic_distribution_from_header','line_number', 'nomen_manda_0/id','nomen_manda_1/id','nomen_manda_2/id','nomen_manda_3/id', 'nomenclature_description','notes','default_name','default_code','date_planned','is_line_split', 'original_line_id/id', 'confirmed_delivery_date', 'stock_take_date', 'cancel_split_ok']","[('order_id.partner_type', '!=', 'external'), ('state', '!=', 'draft')]",partner_id,MISSION,purchase.order.line.sol_update_original_pol,sale.order.line,FO line updates PO line,12,Valid |
1501 | msf_sync_data_server.partial_shipped_coordo_updates_in_at_project,TRUE,TRUE,"['name', 'state', 'origin', 'partner_type_stock_picking', 'shipment_id/name', 'min_date', 'note', 'move_lines/processed_stock_move', 'move_lines/id', 'move_lines/state','move_lines/original_qty_partial', 'move_lines/line_number', 'move_lines/name', 'move_lines/change_reason', 'move_lines/product_id/id', 'move_lines/product_id/name', 'move_lines/product_qty', 'move_lines/prodlot_id/id','move_lines/prodlot_id/name','move_lines/prodlot_id/life_date', 'move_lines/expired_date', 'move_lines/asset_id/id','move_lines/product_uom/id', 'move_lines/product_uom/name', 'move_lines/date', 'move_lines/date_expected', 'move_lines/note', 'move_lines/location_dest_id/usage', 'move_lines/comment']","['&','&','&','&','&','&',('partner_type_stock_picking', '!=', 'external'), ('type', '=', 'out'), ('subtype', 'in', ['standard', 'packing']), ('state', '=', 'done'), ('already_shipped', '=', True), ('do_not_sync', '=', False), ('claim', '=', False)]",partner_id,MISSION,stock.picking.partial_shipped_fo_updates_in_po,stock.picking,Partial shipped at Coordo updates IN at Project,19,Valid |
1502 | msf_sync_data_server.moves_from_dpo_closed_coordo_updates_in_at_project,TRUE,TRUE,"['name', 'state', 'origin', 'subtype', 'partner_type_stock_picking', 'shipment_id/name', 'min_date', 'note', 'move_lines/processed_stock_move', 'move_lines/id', 'move_lines/state','move_lines/original_qty_partial', 'move_lines/line_number', 'move_lines/name', 'move_lines/change_reason', 'move_lines/product_id/id', 'move_lines/product_id/name', 'move_lines/product_qty', 'move_lines/prodlot_id/id','move_lines/prodlot_id/name','move_lines/prodlot_id/life_date', 'move_lines/expired_date', 'move_lines/asset_id/id','move_lines/product_uom/id', 'move_lines/product_uom/name', 'move_lines/date', 'move_lines/date_expected', 'move_lines/note', 'move_lines/dpo_line_id', 'move_lines/comment']","['&', '&', '&', ('partner_type_stock_picking', '!=', 'external'), ('type', '=', 'out'), ('subtype', 'in', ['picking', 'standard']), ('dpo_out', '=', True)]",partner_id,MISSION,stock.picking.partial_shippped_dpo_updates_in_po,stock.picking,Moves from DPO closed at Coordo updates IN at Project,20,Valid |
1503 | -msf_sync_data_server.dpo_service_lines_update_in_at_project,FALSE,TRUE,"['order_id/name', 'order_id/delivery_confirmed_date', 'fake_id', 'origin', 'confirmed_delivery_date', 'name', 'product_uom/id', 'product_uom/name', 'link_sol_id/line_number', 'notes', 'product_qty', 'product_id/name', 'product_id/id', 'comment']","[('dest_partner_id.partner_type', '=', 'internal'), ('order_id.order_type', '=', 'direct'), ('order_id.state', 'in', ['approved', 'done']), ('product_id.type', 'in', ['service', 'service_recep'])]",dest_partner_id,MISSION,purchase.order.line.confirmed_dpo_service_lines_update_in_po,purchase.order.line,DPO service lines update IN at Project,21,Valid |
1504 | +msf_sync_data_server.dpo_service_lines_update_in_at_project,FALSE,TRUE,"['order_id/name', 'order_id/delivery_confirmed_date', 'sync_local_id', 'origin', 'confirmed_delivery_date', 'name', 'product_uom/id', 'product_uom/name', 'link_sol_id/line_number', 'notes', 'product_qty', 'product_id/name', 'product_id/id', 'comment']","[('dest_partner_id.partner_type', '=', 'internal'), ('order_id.order_type', '=', 'direct'), ('order_id.state', 'in', ['approved', 'done']), ('product_id.type', 'in', ['service', 'service_recep'])]",dest_partner_id,MISSION,purchase.order.line.confirmed_dpo_service_lines_update_in_po,purchase.order.line,DPO service lines update IN at Project,21,Valid |
1505 | msf_sync_data_server.cancel_out_at_coordo_cancels_in_at_project,TRUE,TRUE,"['name', 'state', 'origin']","['&','&','&','&',('partner_type_stock_picking', '!=', 'external'), ('type', '=', 'out'),('state', '=', 'cancel'),('subtype', '=', 'standard'),('do_not_sync', '=', False)]",partner_id,MISSION,stock.picking.cancel_out_pick_cancel_in,stock.picking,Canceled OUT at Coordo cancels IN at Project,22,Valid |
1506 | msf_sync_data_server.cancel_pick_at_coordo_cancels_in_at_project,TRUE,TRUE,"['name', 'state', 'origin']","['&','&','&','&','&',('partner_type_stock_picking', '!=', 'external'), ('type', '=', 'out'),('state', '=', 'cancel'),('subtype', '=', 'picking'),('backorder_id', '=', False),('do_not_sync', '=', False)]",partner_id,MISSION,stock.picking.cancel_out_pick_cancel_in,stock.picking,Canceled PICK at Coordo cancels IN at Project,23,Valid |
1507 | msf_sync_data_server.cancel_stock_move_at_coordo_cancels_in_at_project,TRUE,TRUE,"['name', 'state', 'origin', 'date_cancel']","['&','&','&','&','&','&',('picking_id.partner_type_stock_picking', '!=', 'external'), ('type', '=', 'out'),('state', '=', 'cancel'),('picking_id.state', '=', 'done'),('picking_id.do_not_sync', '=', False),('to_be_sent', '=', True), '&', '|', ('picking_id.subtype', '=', 'picking'), ('picking_id.subtype', '=', 'standard'), ('picking_id.already_shipped', '=', False)]",partner_id,MISSION,stock.picking.cancel_stock_move_of_pick_cancel_in,stock.move,Canceled stock move cancels IN,24,Valid |
1508 | |
1509 | === modified file 'bin/addons/order_types/__openerp__.py' |
1510 | --- bin/addons/order_types/__openerp__.py 2012-06-13 15:32:42 +0000 |
1511 | +++ bin/addons/order_types/__openerp__.py 2017-10-02 12:34:11 +0000 |
1512 | @@ -30,7 +30,6 @@ |
1513 | "stock", |
1514 | "product_expiry", |
1515 | "purchase_double_validation", |
1516 | - "sale_override", |
1517 | "purchase_override"], |
1518 | "author": "TeMPO Consulting, MSF", |
1519 | "website": "", |
1520 | |
1521 | === modified file 'bin/addons/procurement_request/__openerp__.py' |
1522 | --- bin/addons/procurement_request/__openerp__.py 2013-09-16 06:13:17 +0000 |
1523 | +++ bin/addons/procurement_request/__openerp__.py 2017-10-02 12:34:11 +0000 |
1524 | @@ -2,7 +2,7 @@ |
1525 | ############################################################################## |
1526 | # |
1527 | # OpenERP, Open Source Management Solution |
1528 | -# Copyright (C) 2011 TeMPO Consulting, MSF |
1529 | +# Copyright (C) 2011 TeMPO Consulting, MSF |
1530 | # |
1531 | # This program is free software: you can redistribute it and/or modify |
1532 | # it under the terms of the GNU Affero General Public License as |
1533 | @@ -22,16 +22,15 @@ |
1534 | { |
1535 | "name": "Internal Request", |
1536 | "version": "1.0", |
1537 | - "depends": ["base", |
1538 | - "sale", |
1539 | - "sale_override", |
1540 | - "stock_override", |
1541 | - "msf_order_date", |
1542 | + "depends": ["base", |
1543 | + "sale", |
1544 | + "stock_override", |
1545 | + "msf_order_date", |
1546 | "stock", |
1547 | "threshold_value", |
1548 | "procurement_cycle", |
1549 | "procurement_auto", |
1550 | - ], |
1551 | + ], |
1552 | "author": "TeMPO Consulting, MSF", |
1553 | "website": "", |
1554 | "category": "Sales & Purchases", |
1555 | @@ -44,7 +43,6 @@ |
1556 | 'update_xml': [ |
1557 | 'procurement_request_view.xml', |
1558 | 'procurement_request_sequence.xml', |
1559 | - 'procurement_request_workflow.xml', |
1560 | 'procurement_request_wizard.xml', |
1561 | 'procurement_request_report.xml', |
1562 | 'wizard/wizard_import_list_view.xml', |
1563 | @@ -59,7 +57,7 @@ |
1564 | ], |
1565 | 'installable': True, |
1566 | 'active': False, |
1567 | -# 'certificate': 'certificate', |
1568 | + # 'certificate': 'certificate', |
1569 | } |
1570 | |
1571 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
1572 | |
1573 | === modified file 'bin/addons/procurement_request/procurement_request.py' |
1574 | --- bin/addons/procurement_request/procurement_request.py 2017-08-25 15:37:51 +0000 |
1575 | +++ bin/addons/procurement_request/procurement_request.py 2017-10-02 12:34:11 +0000 |
1576 | @@ -25,7 +25,6 @@ |
1577 | from tools.translate import _ |
1578 | import decimal_precision as dp |
1579 | |
1580 | -from sale_override import SALE_ORDER_STATE_SELECTION |
1581 | from msf_order_date.order_dates import compute_rts |
1582 | |
1583 | |
1584 | @@ -353,7 +352,6 @@ |
1585 | 'sale.order.line': (_get_order, ['price_unit', 'tax_id', 'discount', 'product_uom_qty', 'type'], 10), |
1586 | }, |
1587 | multi='by_type', help="The amount of lines sourced from stock"), |
1588 | - 'state': fields.selection(SALE_ORDER_STATE_SELECTION, 'Order State', readonly=True, help="Gives the state of the quotation or sales order. \nThe exception state is automatically set when a cancel operation occurs in the invoice validation (Invoice Exception) or in the picking list process (Shipping Exception). \nThe 'Waiting Schedule' state is set when the invoice is confirmed but waiting for the scheduler to run on the date 'Ordered Date'.", select=True), |
1589 | 'name': fields.char('Order Reference', size=64, required=True, readonly=True, select=True), |
1590 | 'is_ir_from_po_cancel': fields.boolean('Is IR from a PO cancelled', invisible=True), # UFTP-82: flagging we are in an IR and its PO is cancelled |
1591 | } |
1592 | @@ -568,59 +566,6 @@ |
1593 | |
1594 | return True |
1595 | |
1596 | - def confirm_procurement(self, cr, uid, ids, context=None): |
1597 | - ''' |
1598 | - Confirmed the request |
1599 | - ''' |
1600 | - if context is None: |
1601 | - context = {} |
1602 | - |
1603 | - self.write(cr, uid, ids, {'state': 'progress'}, context=context) |
1604 | - |
1605 | - for request in self.browse(cr, uid, ids, context=context): |
1606 | - if len(request.order_line) <= 0: |
1607 | - raise osv.except_osv(_('Error'), _('You cannot confirm an Internal request with no lines !')) |
1608 | - for line in request.order_line: |
1609 | - # for FO |
1610 | - if line.type == 'make_to_order' and not line.po_cft == 'cft': |
1611 | - if not line.supplier: |
1612 | - line_number = line.line_number |
1613 | - request_name = request.name |
1614 | - raise osv.except_osv(_('Error'), _('Please correct the line %s of the %s: the supplier is required for the procurement method "On Order" !') % (line_number, request_name)) |
1615 | - # an Internal Request without product can only have Internal, Intersection or Intermission partners. |
1616 | - elif line.supplier and not line.product_id and line.order_id.procurement_request and line.supplier.partner_type not in ['internal', 'section', 'intermission', 'esc']: |
1617 | - raise osv.except_osv(_('Warning'), _("""For an Internal Request with a procurement method 'On Order' and without product, |
1618 | - the supplier must be either in 'Internal', 'Inter-Section', 'Intermission' or 'ESC' type. |
1619 | - """)) |
1620 | - message = _("The internal request '%s' has been confirmed (nb lines: %s).") % (request.name, len(request.order_line)) |
1621 | - proc_view = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'procurement_request', 'procurement_request_form_view') |
1622 | - context.update({'view_id': proc_view and proc_view[1] or False}) |
1623 | - self.log(cr, uid, request.id, message, context=context) |
1624 | - |
1625 | - self.action_ship_create(cr, uid, ids, context=context) |
1626 | - |
1627 | - return True |
1628 | - |
1629 | - def test_state_done(self, cr, uid, ids, mode, *args): |
1630 | - if not self.test_state(cr, uid, ids, mode, *args): |
1631 | - return False |
1632 | - |
1633 | - for ir in self.browse(cr, uid, ids): |
1634 | - is_out = ir.location_requestor_id.usage == 'customer' |
1635 | - if not is_out: |
1636 | - return True |
1637 | - |
1638 | - ir_lines = [x.id for x in ir.order_line] |
1639 | - out_move_ids = self.pool.get('stock.move').search(cr, uid, [ |
1640 | - ('picking_id.type', '=', 'out'), |
1641 | - ('sale_line_id', 'in', ir_lines), |
1642 | - ('state', 'not in', ['done', 'cancel']), |
1643 | - ]) |
1644 | - if out_move_ids: |
1645 | - return False |
1646 | - |
1647 | - return True |
1648 | - |
1649 | def procurement_done(self, cr, uid, ids, context=None): |
1650 | ''' |
1651 | Creates all procurement orders according to lines |
1652 | @@ -675,27 +620,6 @@ |
1653 | _name = 'sale.order.line' |
1654 | _inherit = 'sale.order.line' |
1655 | |
1656 | - def _amount_line(self, cr, uid, ids, field_name, arg, context=None): |
1657 | - ''' |
1658 | - Override the method to return 0.0 if the line is a procurement request line |
1659 | - ''' |
1660 | - res = {} |
1661 | - new_ids = [] |
1662 | - cur_obj = self.pool.get('res.currency') |
1663 | - curr_browse = self.pool.get('res.users').browse(cr, uid, [uid], context)[0].company_id.currency_id |
1664 | - for line in self.browse(cr, uid, ids): |
1665 | - if line.order_id.procurement_request: |
1666 | - subtotal = line.cost_price * line.product_uom_qty |
1667 | - res[line.id] = cur_obj.round(cr, uid, curr_browse.rounding, subtotal) |
1668 | - if line.cost_price > 0 and res[line.id] < 0.01: |
1669 | - res[line.id] = 0.01 |
1670 | - else: |
1671 | - new_ids.append(line.id) |
1672 | - |
1673 | - res.update(super(procurement_request_line, self)._amount_line(cr, uid, new_ids, field_name, arg, context=context)) |
1674 | - |
1675 | - return res |
1676 | - |
1677 | def create(self, cr, uid, vals, context=None): |
1678 | ''' |
1679 | Adds the date_planned value. |
1680 | @@ -764,7 +688,6 @@ |
1681 | 'cost_price': fields.float(string='Cost price', digits_compute=dp.get_precision('Sale Price Computation')), |
1682 | 'procurement_request': fields.boolean(string='Internal Request', readonly=True), |
1683 | 'latest': fields.char(size=64, string='Latest documents', readonly=True), |
1684 | - 'price_subtotal': fields.function(_amount_line, method=True, string='Subtotal', digits_compute=dp.get_precision('Sale Price')), |
1685 | 'my_company_id': fields.many2one('res.company', 'Company', select=1), |
1686 | 'supplier': fields.many2one('res.partner', 'Supplier', domain="[('id', '!=', my_company_id)]"), |
1687 | # openerp bug: eval invisible in p.o use the po line state and not the po state ! |
1688 | @@ -831,8 +754,14 @@ |
1689 | res, test = product_obj._on_change_restriction_error(cr, uid, product_id, field_name='product_id', values={'value': vals['value']}, vals={'constraints': 'consumption'}, context=context) |
1690 | if test: |
1691 | return res |
1692 | - vals['value'] = {'product_uom': product.uom_id.id, 'name': '[%s] %s' % (product.default_code, product.name), |
1693 | - 'type': product.procure_method, 'comment_ok': True, 'cost_price': product.standard_price, } |
1694 | + vals['value'] = { |
1695 | + 'product_uom': product.uom_id.id, |
1696 | + 'name': '[%s] %s' % (product.default_code, product.name), |
1697 | + 'type': product.procure_method, |
1698 | + 'comment_ok': True, |
1699 | + 'cost_price': product.standard_price, |
1700 | + 'price_unit': product.list_price, |
1701 | + } |
1702 | if vals['value']['type'] != 'make_to_stock': |
1703 | vals['value'].update({'supplier': product.seller_ids and product.seller_ids[0].name.id}) |
1704 | uom_val = uom_obj.read(cr, uid, [product.uom_id.id], ['category_id']) |
1705 | @@ -892,42 +821,5 @@ |
1706 | |
1707 | procurement_request_line() |
1708 | |
1709 | -class purchase_order(osv.osv): |
1710 | - _name = 'purchase.order' |
1711 | - _inherit = 'purchase.order' |
1712 | - |
1713 | - def _hook_action_picking_create_modify_out_source_loc_check(self, cr, uid, ids, context=None, *args, **kwargs): |
1714 | - ''' |
1715 | - Please copy this to your module's method also. |
1716 | - This hook belongs to the action_picking_create method from purchase>purchase.py>purchase_order class |
1717 | - |
1718 | - - allow to choose whether or not the source location of the corresponding outgoing stock move should |
1719 | - match the destination location of incoming stock move |
1720 | - ''' |
1721 | - order_line = kwargs['order_line'] |
1722 | - move_id = kwargs['move_id'] |
1723 | - proc_obj = self.pool.get('procurement.order') |
1724 | - move_obj = self.pool.get('stock.move') |
1725 | - sale_line_obj = self.pool.get('sale.order.line') |
1726 | - po_line_obj = self.pool.get('purchase.order.line') |
1727 | - # If the line comes from an ISR and it's not splitted line, |
1728 | - # change the move_dest_id of this line (and their children) |
1729 | - # to match with the procurement ordre move destination |
1730 | - if order_line.move_dest_id and not order_line.is_line_split: # UTP-972: Use the boolean for split line |
1731 | - proc_ids = proc_obj.search(cr, uid, [('move_id', '=', order_line.move_dest_id.id)], context=context) |
1732 | - so_line_ids = sale_line_obj.search(cr, uid, [('procurement_id', 'in', proc_ids)], context=context) |
1733 | - po_line_ids = po_line_obj.search(cr, uid, [('move_dest_id', '=', order_line.move_dest_id.id)], context=context) |
1734 | - if so_line_ids and all(not line.order_id or (line.order_id.procurement_request and line.order_id.location_requestor_id.usage != 'customer') for line in sale_line_obj.browse(cr, uid, so_line_ids, context=context)): |
1735 | - for proc in proc_obj.browse(cr, uid, proc_ids, context=context): |
1736 | - if proc.move_id: |
1737 | - move_obj.write(cr, uid, [proc.move_id.id], {'state': 'draft'}, context=context) |
1738 | - move_obj.unlink(cr, uid, [proc.move_id.id], context=context) |
1739 | - proc_obj.write(cr, uid, [proc.id], {'move_id': move_id}, context=context) |
1740 | - # Update the move_dest_id of all children to avoid the system to deal with a deleted stock move |
1741 | - po_line_obj.write(cr, uid, po_line_ids, {'move_dest_id': move_id}, context=context) |
1742 | - |
1743 | - return super(purchase_order, self)._hook_action_picking_create_modify_out_source_loc_check(cr, uid, ids, context, *args, **kwargs) |
1744 | - |
1745 | -purchase_order() |
1746 | |
1747 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
1748 | |
1749 | === modified file 'bin/addons/procurement_request/procurement_request_view.xml' |
1750 | --- bin/addons/procurement_request/procurement_request_view.xml 2017-09-06 10:03:46 +0000 |
1751 | +++ bin/addons/procurement_request/procurement_request_view.xml 2017-10-02 12:34:11 +0000 |
1752 | @@ -38,7 +38,7 @@ |
1753 | <field name="priority" eval="250" /> |
1754 | <field name="arch" type="xml"> |
1755 | <form string="Internal Request"> |
1756 | - <group colspan="6" attrs="{'invisible': [('state', '!=', 'validated')]}"> |
1757 | + <group colspan="6" attrs="{'invisible': [('state', 'not in', ['validated', 'validated_p'])]}"> |
1758 | <html> |
1759 | <p style="text-align:center; color: red; font-weight: bold; font-size: 1.2em;"> |
1760 | WARNING: This document has already been validated, are you sure you wish to modify after validation? |
1761 | @@ -47,12 +47,12 @@ |
1762 | </group> |
1763 | <group col="6" colspan="4" name="header"> |
1764 | <field name="name" /> |
1765 | - <field name="date_order" attrs="{'readonly': [('state', 'not in', ['draft', 'validated'])]}" /> |
1766 | - <field name="warehouse_id" widget="selection" attrs="{'readonly': [('state', 'not in', ['draft', 'validated'])]}" /> |
1767 | - <field name="requestor" attrs="{'readonly': [('state', 'not in', ['draft', 'validated'])]}" /> |
1768 | - <field name="location_requestor_id" required="1" attrs="{'readonly': [('state', 'not in', ['draft', 'validated'])]}" /> |
1769 | - <field name="delivery_requested_date" required="1" string="Requested date" attrs="{'readonly': [('state', 'not in', ['draft', 'validated'])]}" /> |
1770 | - <field name="origin" attrs="{'readonly': [('state', 'not in', ['draft', 'validated'])]}" /> |
1771 | + <field name="date_order" attrs="{'readonly': [('state', 'not in', ['draft', 'draft_p', 'validated', 'validated_p'])]}" /> |
1772 | + <field name="warehouse_id" widget="selection" attrs="{'readonly': [('state', 'not in', ['draft', 'draft_p', 'validated', 'validated_p'])]}" /> |
1773 | + <field name="requestor" attrs="{'readonly': [('state', 'not in', ['draft', 'draft_p', 'validated', 'validated_p'])]}" /> |
1774 | + <field name="location_requestor_id" required="1" attrs="{'readonly': [('state', 'not in', ['draft', 'draft_p', 'validated', 'validated_p'])]}" /> |
1775 | + <field name="delivery_requested_date" required="1" string="Requested date" attrs="{'readonly': [('state', 'not in', ['draft', 'draft_p', 'validated', 'validated_p'])]}" /> |
1776 | + <field name="origin" attrs="{'readonly': [('state', 'not in', ['draft', 'draft_p', 'validated', 'validated_p'])]}" /> |
1777 | <field name="functional_currency_id" /> |
1778 | <field name="categ" on_change="onchange_categ(categ)" /> |
1779 | <group colspan="2" col="3"> |
1780 | @@ -66,7 +66,7 @@ |
1781 | <notebook colspan="5"> |
1782 | <page string="Products"> |
1783 | <button colspan="4" string="Round Qty to SoQ" type="object" name="round_to_soq" icon="gtk-execute" attrs="{'invisible': [('state', '!=', 'draft')]}" /> |
1784 | - <field name="order_line" mode="tree,form" colspan="4" nolabel="1" attrs="{'readonly': [('state', 'not in', ['draft', 'validated'])]}"> |
1785 | + <field name="order_line" mode="tree,form" colspan="4" nolabel="1" attrs="{'readonly': [('state', 'not in', ['draft', 'draft_p', 'validated', 'validated_p'])]}"> |
1786 | <tree string="Products" editable="top" > |
1787 | <field name="product_id" on_change="requested_product_id_change(product_id, comment, parent.categ)" |
1788 | context="available_for_restriction='consumption',search_default_not_restricted=1" |
1789 | @@ -87,14 +87,15 @@ |
1790 | <button name="open_order_line_to_correct" |
1791 | string="Configurator" |
1792 | type="object" |
1793 | - attrs="{'invisible': ['|', ('product_id_ok', '=', True), ('state', 'not in', ['draft', 'validated'])]}" |
1794 | + attrs="{'invisible': ['|', ('product_id_ok', '=', True), ('state', 'not in', ['draft', 'draft_p', 'validated', 'validated_p'])]}" |
1795 | icon="terp-go-week" /> |
1796 | <field name="product_uom_qty" on_change="onchange_uom(product_id, product_uom, product_uom_qty)" /> |
1797 | - <field name="cost_price" string="Cost Price (FC)" /> |
1798 | + <field name="price_unit"/> |
1799 | <field name="notes" /> |
1800 | + <field name="display_resourced_orig_line" /> |
1801 | <field name="display_confirm_button" invisible="1" /> |
1802 | <field name="type" on_change="requested_type_change(product_id, type)" |
1803 | - attrs="{'readonly': [('fake_state', 'not in', ['draft', 'validated']), ('display_confirm_button', '=', False)]}" |
1804 | + attrs="{'readonly': [('fake_state', 'not in', ['draft', 'draft_p', 'validated', 'validated_p']), ('display_confirm_button', '=', False)]}" |
1805 | /> |
1806 | <field name="my_company_id" invisible="1" /> |
1807 | <!-- utp-357: the supplier will be selected in the sourcing tool --> |
1808 | @@ -103,15 +104,17 @@ |
1809 | attrs="{'readonly': [('type', '=', 'make_to_stock')]}" |
1810 | domain="[('supplier', '=', True), ('id', '!=', my_company_id), ('check_partner_ir', '=', True)]" |
1811 | /> |
1812 | - <field name="fake_state" invisible="1" /> |
1813 | + <field name="fake_state" invisible="1"/> |
1814 | + <field name="state_to_display"/> |
1815 | <field name="stock_take_date"/> |
1816 | <field name="price_subtotal" sum="Total"/> |
1817 | <button name="open_split_wizard" |
1818 | type="object" |
1819 | string="Split Line" |
1820 | icon="terp-stock_effects-object-colorize" |
1821 | - attrs="{'invisible': [('fake_state', 'in', ('confirmed', 'cancel', 'done', 'exception'))]}" |
1822 | + attrs="{'invisible': [('fake_state', 'in', ('confirmed', 'cancel', 'cancel_r', 'done', 'exception'))]}" |
1823 | /> |
1824 | + <button string="Validate" icon="terp-check" name="validated" type="workflow" attrs="{'invisible': [('fake_state', '!=', 'draft')]}"/> |
1825 | </tree> |
1826 | <form> |
1827 | <field name="product_id" colspan="4" /> |
1828 | @@ -126,9 +129,8 @@ |
1829 | </field> |
1830 | <group colspan="4" col="6"> |
1831 | <field name="state" /> |
1832 | - <button name="procurement_cancel" icon="gtk-cancel" string="Cancel" states="draft,validated" context="{'noraise': True}" /> |
1833 | - <button name="procurement_validate" icon="terp-check" string="Validate" states="draft" /> |
1834 | - <button name="procurement_confirm" icon="gtk-execute" string="Confirm" states="validated" confirm="You are about to confirm the Internal Request without going through the sourcing tool. Are you sure?" /> |
1835 | + <button name="procurement_cancel" icon="gtk-cancel" string="Cancel" states="draft,draft_p,validated,validated_p" context="{'noraise': True}" /> |
1836 | + <button name="validate_lines" type="object" string="Validate Lines" icon="terp-check" states="draft,draft_p" attrs="{'readonly': [('no_line', '=', True)]}" /> |
1837 | </group> |
1838 | </page> |
1839 | <page string="Sourcing Documents"> |
1840 | |
1841 | === removed file 'bin/addons/procurement_request/procurement_request_workflow.xml' |
1842 | --- bin/addons/procurement_request/procurement_request_workflow.xml 2015-11-10 13:23:06 +0000 |
1843 | +++ bin/addons/procurement_request/procurement_request_workflow.xml 1970-01-01 00:00:00 +0000 |
1844 | @@ -1,86 +0,0 @@ |
1845 | -<?xml version="1.0" encoding="utf-8" ?> |
1846 | -<openerp> |
1847 | - <data> |
1848 | - |
1849 | - <record id="sale.act_draft" model="workflow.activity"> |
1850 | - <field name="flow_start" eval="True" /> |
1851 | - <field name="kind">dummy</field> |
1852 | - </record> |
1853 | - |
1854 | - <record id="act_procurement" model="workflow.activity"> |
1855 | - <field name="wkf_id" ref="sale.wkf_sale"/> |
1856 | - <field name="flow_start" eval="False" /> |
1857 | - <field name="kind">dummy</field> |
1858 | - <field name="name">procurement</field> |
1859 | - </record> |
1860 | - |
1861 | - <record id="act_proc_validate" model="workflow.activity"> |
1862 | - <field name="wkf_id" ref="sale.wkf_sale" /> |
1863 | - <field name="name">procurement_validate</field> |
1864 | - <field name="kind">function</field> |
1865 | - <field name="action">validate_procurement()</field> |
1866 | - </record> |
1867 | - <record id="act_proc_confirm" model="workflow.activity"> |
1868 | - <field name="wkf_id" ref="sale.wkf_sale" /> |
1869 | - <field name="name">procurement_confirm</field> |
1870 | - <field name="kind">function</field> |
1871 | - <field name="action">confirm_procurement()</field> |
1872 | - </record> |
1873 | - <record id="act_proc_cancel" model="workflow.activity"> |
1874 | - <field name="wkf_id" ref="sale.wkf_sale" /> |
1875 | - <field name="name">procurement_cancel</field> |
1876 | - <field name="flow_stop">True</field> |
1877 | - <field name="kind">function</field> |
1878 | - <field name="action">wkf_action_cancel()</field> |
1879 | - </record> |
1880 | - <record id="act_proc_done" model="workflow.activity"> |
1881 | - <field name="wkf_id" ref="sale.wkf_sale" /> |
1882 | - <field name="flow_stop">True</field> |
1883 | - <field name="name">procurement_done</field> |
1884 | - <field name="kind">function</field> |
1885 | - <field name="action">procurement_done()</field> |
1886 | - </record> |
1887 | - |
1888 | - <record id="trans_proc_draft" model="workflow.transition"> |
1889 | - <field name="act_from" ref="sale.act_draft"/> |
1890 | - <field name="act_to" ref="act_procurement"/> |
1891 | - <field name="condition">procurement_request==True</field> |
1892 | - </record> |
1893 | - |
1894 | - <record id="trans_proc_validate" model="workflow.transition"> |
1895 | - <field name="act_from" ref="act_procurement"/> |
1896 | - <field name="act_to" ref="act_proc_validate"/> |
1897 | - <field name="condition">procurement_request==True</field> |
1898 | - <field name="signal">procurement_validate</field> |
1899 | - </record> |
1900 | - <record id="trans_proc_validate_confirm" model="workflow.transition"> |
1901 | - <field name="act_from" ref="act_proc_validate"/> |
1902 | - <field name="act_to" ref="act_proc_confirm"/> |
1903 | - <field name="condition">procurement_request==True</field> |
1904 | - <field name="signal">procurement_confirm</field> |
1905 | - </record> |
1906 | - <record id="trans_validate_cancel" model="workflow.transition"> |
1907 | - <field name="act_from" ref="act_proc_validate"/> |
1908 | - <field name="act_to" ref="act_proc_cancel"/> |
1909 | - <field name="signal">procurement_cancel</field> |
1910 | - </record> |
1911 | - <record id="trans_procurement_cancel" model="workflow.transition"> |
1912 | - <field name="act_from" ref="act_procurement"/> |
1913 | - <field name="act_to" ref="act_proc_cancel"/> |
1914 | - <field name="signal">procurement_cancel</field> |
1915 | - </record> |
1916 | - <record id="trans_confirm_proc_cancel" model="workflow.transition"> |
1917 | - <field name="act_from" ref="act_proc_confirm"/> |
1918 | - <field name="act_to" ref="act_proc_cancel"/> |
1919 | - <field name="signal">procurement_cancel</field> |
1920 | - </record> |
1921 | - <record id="trans_confirm_proc_done" model="workflow.transition"> |
1922 | - <field name="act_from" ref="act_proc_confirm"/> |
1923 | - <field name="act_to" ref="act_proc_done"/> |
1924 | - <field name="trigger_model">procurement.order</field> |
1925 | - <field name="trigger_expr_id">procurement_lines_get()</field> |
1926 | - <field name="condition"> test_state_done('finished')</field> |
1927 | - </record> |
1928 | - |
1929 | - </data> |
1930 | -</openerp> |
1931 | |
1932 | === modified file 'bin/addons/purchase/__init__.py' |
1933 | --- bin/addons/purchase/__init__.py 2011-01-14 00:11:01 +0000 |
1934 | +++ bin/addons/purchase/__init__.py 2017-10-02 12:34:11 +0000 |
1935 | @@ -20,12 +20,14 @@ |
1936 | ############################################################################## |
1937 | |
1938 | import purchase |
1939 | +import purchase_line |
1940 | +import purchase_workflow |
1941 | import partner |
1942 | import stock |
1943 | import wizard |
1944 | import report |
1945 | import stock |
1946 | import company |
1947 | - |
1948 | +import procurement_order |
1949 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
1950 | |
1951 | |
1952 | === modified file 'bin/addons/purchase/__openerp__.py' |
1953 | --- bin/addons/purchase/__openerp__.py 2012-05-25 13:29:26 +0000 |
1954 | +++ bin/addons/purchase/__openerp__.py 2017-10-02 12:34:11 +0000 |
1955 | @@ -39,13 +39,13 @@ |
1956 | 'data': [ |
1957 | 'security/purchase_security.xml', |
1958 | 'security/ir.model.access.csv', |
1959 | - 'purchase_workflow.xml', |
1960 | 'purchase_sequence.xml', |
1961 | 'company_view.xml', |
1962 | 'purchase_data.xml', |
1963 | 'wizard/purchase_order_group_view.xml', |
1964 | 'wizard/purchase_installer.xml', |
1965 | 'wizard/purchase_line_invoice_view.xml', |
1966 | + 'wizard/purchase_line_cancel_view.xml', |
1967 | 'purchase_report.xml', |
1968 | 'purchase_view.xml', |
1969 | 'stock_view.xml', |
1970 | @@ -53,9 +53,10 @@ |
1971 | #'process/purchase_process.xml', |
1972 | 'report/purchase_report_view.xml', |
1973 | 'board_purchase_view.xml', |
1974 | + 'purchase_line_workflow.xml', |
1975 | ], |
1976 | 'test': [ |
1977 | - 'test/purchase_from_order.yml', |
1978 | + 'test/purchase_from_order.yml', |
1979 | 'test/purchase_from_manual.yml', |
1980 | 'test/purchase_from_picking.yml', |
1981 | 'purchase_unit_test.xml', |
1982 | |
1983 | === modified file 'bin/addons/purchase/process/purchase_process.xml' |
1984 | --- bin/addons/purchase/process/purchase_process.xml 2011-01-14 00:11:01 +0000 |
1985 | +++ bin/addons/purchase/process/purchase_process.xml 2017-10-02 12:34:11 +0000 |
1986 | @@ -157,7 +157,7 @@ |
1987 | <field model="process.node" name="target_node_id" ref="account.process_node_supplierdraftinvoices0"/> |
1988 | <field model="process.node" name="source_node_id" ref="process_node_productrecept0"/> |
1989 | </record> |
1990 | - |
1991 | + <!-- |
1992 | <record id="process_transition_confirmingpurchaseorder0" model="process.transition"> |
1993 | <field eval="[(6,0,[])]" name="transition_ids"/> |
1994 | <field eval=""""Confirmation"""" name="name"/> |
1995 | @@ -166,6 +166,7 @@ |
1996 | <field model="process.node" name="source_node_id" ref="process_node_draftpurchaseorder0"/> |
1997 | <field eval="[(6,0,[ref('purchase.trans_draft_confirmed')])]" name="transition_ids"/> |
1998 | </record> |
1999 | + --> |
2000 | |
2001 | <record id="process_transition_confirmingpurchaseorder1" model="process.transition"> |
2002 | <field eval="[(6,0,[])]" name="transition_ids"/> |
2003 | |
2004 | === added file 'bin/addons/purchase/procurement_order.py' |
2005 | --- bin/addons/purchase/procurement_order.py 1970-01-01 00:00:00 +0000 |
2006 | +++ bin/addons/purchase/procurement_order.py 2017-10-02 12:34:11 +0000 |
2007 | @@ -0,0 +1,152 @@ |
2008 | +# -*- coding: utf-8 -*- |
2009 | + |
2010 | +from datetime import datetime |
2011 | +from dateutil.relativedelta import relativedelta |
2012 | + |
2013 | +from osv import osv, fields |
2014 | + |
2015 | + |
2016 | +class procurement_order(osv.osv): |
2017 | + _inherit = 'procurement.order' |
2018 | + _columns = { |
2019 | + 'purchase_id': fields.many2one('purchase.order', 'Purchase Order'), |
2020 | + } |
2021 | + |
2022 | + def action_po_assign(self, cr, uid, ids, context=None): |
2023 | + """ This is action which call from workflow to assign purchase order to procurements |
2024 | + @return: True |
2025 | + """ |
2026 | + res = self.make_po(cr, uid, ids, context=context) |
2027 | + res = res.values() |
2028 | + return len(res) and res[0] or 0 #TO CHECK: why workflow is generated error if return not integer value |
2029 | + |
2030 | + def get_partner_hook(self, cr, uid, ids, context=None, *args, **kwargs): |
2031 | + ''' |
2032 | + return a dictionary with partner, seller_qty and seller_delay |
2033 | + ''' |
2034 | + result = {} |
2035 | + |
2036 | + procurement = kwargs['procurement'] |
2037 | + partner = procurement.product_id.seller_id # Taken Main Supplier of Product of Procurement. |
2038 | + seller_qty = procurement.product_id.seller_qty |
2039 | + seller_delay = int(procurement.product_id.seller_delay) |
2040 | + |
2041 | + result.update(partner=partner, |
2042 | + seller_qty=seller_qty, |
2043 | + seller_delay=seller_delay) |
2044 | + |
2045 | + return result |
2046 | + |
2047 | + def po_line_values_hook(self, cr, uid, ids, context=None, *args, **kwargs): |
2048 | + ''' |
2049 | + Please copy this to your module's method also. |
2050 | + This hook belongs to the make_po method from purchase>purchase.py>procurement_order |
2051 | + |
2052 | + - allow to modify the data for purchase order line creation |
2053 | + ''' |
2054 | + line = kwargs['line'] |
2055 | + return line |
2056 | + |
2057 | + def po_values_hook(self, cr, uid, ids, context=None, *args, **kwargs): |
2058 | + ''' |
2059 | + Please copy this to your module's method also. |
2060 | + This hook belongs to the make_po method from purchase>purchase.py>procurement_order |
2061 | + |
2062 | + - allow to modify the data for purchase order creation |
2063 | + ''' |
2064 | + values = kwargs['values'] |
2065 | + return values |
2066 | + |
2067 | + def create_po_hook(self, cr, uid, ids, context=None, *args, **kwargs): |
2068 | + ''' |
2069 | + creation of purchase order |
2070 | + return the id of newly created po |
2071 | + ''' |
2072 | + po_obj = self.pool.get('purchase.order') |
2073 | + values = kwargs['values'] |
2074 | + purchase_id = po_obj.create(cr, uid, values, context=context) |
2075 | + return purchase_id |
2076 | + |
2077 | + def make_po(self, cr, uid, ids, context=None): |
2078 | + """ Make purchase order from procurement |
2079 | + @return: New created Purchase Orders procurement wise |
2080 | + """ |
2081 | + res = {} |
2082 | + if context is None: |
2083 | + context = {} |
2084 | + company = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id |
2085 | + partner_obj = self.pool.get('res.partner') |
2086 | + uom_obj = self.pool.get('product.uom') |
2087 | + pricelist_obj = self.pool.get('product.pricelist') |
2088 | + prod_obj = self.pool.get('product.product') |
2089 | + acc_pos_obj = self.pool.get('account.fiscal.position') |
2090 | + for procurement in self.browse(cr, uid, ids, context=context): |
2091 | + res_id = procurement.move_id.id |
2092 | + |
2093 | + # partner, seller_qty and seller_delay are computed with hook |
2094 | + hook = self.get_partner_hook(cr, uid, ids, context=context, procurement=procurement) |
2095 | + partner = hook['partner'] |
2096 | + seller_qty = hook['seller_qty'] |
2097 | + seller_delay = hook['seller_delay'] |
2098 | + partner_id = partner.id |
2099 | + address_id = partner_obj.address_get(cr, uid, [partner_id], ['delivery'])['delivery'] |
2100 | + pricelist_id = partner.property_product_pricelist_purchase |
2101 | + |
2102 | + uom_id = procurement.product_id.uom_po_id.id |
2103 | + |
2104 | + qty = uom_obj._compute_qty(cr, uid, procurement.product_uom.id, procurement.product_qty, uom_id) |
2105 | + if seller_qty: |
2106 | + qty = max(qty,seller_qty) |
2107 | + |
2108 | + price = pricelist_obj.price_get(cr, uid, [pricelist_id.id], procurement.product_id.id, qty, partner_id, {'uom': uom_id})[pricelist_id.id] |
2109 | + if hook.get('price_unit', False): |
2110 | + price = hook.get('price_unit', False) |
2111 | + |
2112 | + newdate = datetime.strptime(procurement.date_planned, '%Y-%m-%d %H:%M:%S') |
2113 | + newdate = (newdate - relativedelta(days=int(company.po_lead))) - relativedelta(days=int(seller_delay)) |
2114 | + |
2115 | + #Passing partner_id to context for purchase order line integrity of Line name |
2116 | + context.update({'lang': partner.lang, 'partner_id': partner_id}) |
2117 | + |
2118 | + product = prod_obj.browse(cr, uid, procurement.product_id.id, context=context) |
2119 | + |
2120 | + line = { |
2121 | + 'name': product.partner_ref, |
2122 | + 'product_qty': qty, |
2123 | + 'product_id': procurement.product_id.id, |
2124 | + 'product_uom': uom_id, |
2125 | + 'price_unit': price, |
2126 | + 'date_planned': newdate.strftime('%Y-%m-%d %H:%M:%S'), |
2127 | + 'move_dest_id': res_id, |
2128 | + 'notes': product.description_purchase, |
2129 | + } |
2130 | + |
2131 | + # line values modification from hook |
2132 | + line = self.po_line_values_hook(cr, uid, ids, context=context, line=line, procurement=procurement, pricelist=pricelist_id) |
2133 | + |
2134 | + taxes_ids = procurement.product_id.product_tmpl_id.supplier_taxes_id |
2135 | + taxes = acc_pos_obj.map_tax(cr, uid, partner.property_account_position, taxes_ids) |
2136 | + line.update({ |
2137 | + 'taxes_id': [(6,0,taxes)] |
2138 | + }) |
2139 | + values = { |
2140 | + 'origin': procurement.origin, |
2141 | + 'partner_id': partner_id, |
2142 | + 'partner_address_id': address_id, |
2143 | + 'location_id': procurement.location_id.id, |
2144 | + 'pricelist_id': pricelist_id.id, |
2145 | + 'order_line': [(0,0,line)], |
2146 | + 'company_id': procurement.company_id.id, |
2147 | + 'fiscal_position': partner.property_account_position and partner.property_account_position.id or False, |
2148 | + } |
2149 | + # values modification from hook |
2150 | + values = self.po_values_hook(cr, uid, ids, context=context, values=values, procurement=procurement, line=line,) |
2151 | + # purchase creation from hook |
2152 | + purchase_id = self.create_po_hook(cr, uid, ids, context=context, values=values, procurement=procurement) |
2153 | + res[procurement.id] = purchase_id |
2154 | + self.write(cr, uid, [procurement.id], {'state': 'running', 'purchase_id': purchase_id}) |
2155 | + return res |
2156 | + |
2157 | +procurement_order() |
2158 | + |
2159 | + |
2160 | |
2161 | === modified file 'bin/addons/purchase/purchase.py' |
2162 | --- bin/addons/purchase/purchase.py 2017-08-03 15:16:40 +0000 |
2163 | +++ bin/addons/purchase/purchase.py 2017-10-02 12:34:11 +0000 |
2164 | @@ -20,28 +20,38 @@ |
2165 | ############################################################################## |
2166 | |
2167 | import time |
2168 | -from datetime import datetime |
2169 | -from dateutil.relativedelta import relativedelta |
2170 | - |
2171 | from osv import osv, fields |
2172 | import netsvc |
2173 | -import pooler |
2174 | from tools.translate import _ |
2175 | import decimal_precision as dp |
2176 | from osv.orm import browse_record, browse_null |
2177 | - |
2178 | -# |
2179 | -# Model definition |
2180 | -# |
2181 | +from order_types import ORDER_PRIORITY, ORDER_CATEGORY |
2182 | +import logging |
2183 | +import pooler |
2184 | +import json |
2185 | +import threading |
2186 | +from datetime import datetime |
2187 | +from dateutil.relativedelta import relativedelta |
2188 | +from workflow.wkf_expr import _eval_expr |
2189 | +from purchase_override import PURCHASE_ORDER_STATE_SELECTION |
2190 | +from account_override.period import get_period_from_date |
2191 | +from account_override.period import get_date_in_period |
2192 | + |
2193 | +ORDER_TYPES_SELECTION = [ |
2194 | + ('regular', _('Regular')), |
2195 | + ('donation_exp', _('Donation before expiry')), |
2196 | + ('donation_st', _('Standard donation')), |
2197 | + ('loan', _('Loan')), |
2198 | + ('in_kind', _('In Kind Donation')), |
2199 | + ('purchase_list', _('Purchase List')), |
2200 | + ('direct', _('Direct Purchase Order')), |
2201 | +] |
2202 | + |
2203 | + |
2204 | class purchase_order(osv.osv): |
2205 | - |
2206 | - def _calc_amount(self, cr, uid, ids, prop, unknow_none, unknow_dict): |
2207 | - res = {} |
2208 | - for order in self.browse(cr, uid, ids): |
2209 | - res[order.id] = 0 |
2210 | - for oline in order.order_line: |
2211 | - res[order.id] += oline.price_unit * oline.product_qty |
2212 | - return res |
2213 | + _name = "purchase.order" |
2214 | + _description = "Purchase Order" |
2215 | + _order = "name desc" |
2216 | |
2217 | def _amount_all(self, cr, uid, ids, field_name, arg, context=None): |
2218 | res = {} |
2219 | @@ -91,19 +101,41 @@ |
2220 | res[purchase.id]=min_date |
2221 | return res |
2222 | |
2223 | - |
2224 | def _invoiced_rate(self, cursor, user, ids, name, arg, context=None): |
2225 | res = {} |
2226 | + sp_obj = self.pool.get('stock.picking') |
2227 | + inv_obj = self.pool.get('account.invoice') |
2228 | for purchase in self.browse(cursor, user, ids, context=context): |
2229 | - tot = 0.0 |
2230 | - for invoice in purchase.invoice_ids: |
2231 | - if invoice.state not in ('draft','cancel'): |
2232 | - tot += invoice.amount_untaxed |
2233 | - |
2234 | - if purchase.amount_untaxed: |
2235 | - res[purchase.id] = min(100.0, tot * 100.0 / (purchase.amount_untaxed)) |
2236 | + if ((purchase.order_type == 'regular' and purchase.partner_id.partner_type in ('internal', 'esc')) or \ |
2237 | + purchase.order_type in ['donation_exp', 'donation_st', 'loan', 'in_kind']): |
2238 | + res[purchase.id] = purchase.shipped_rate |
2239 | else: |
2240 | - res[purchase.id] = 0.0 |
2241 | + tot = 0.0 |
2242 | + # UTP-808: Deleted invoices amount should be taken in this process. So what we do: |
2243 | + # 1/ Take all closed stock picking linked to the purchase |
2244 | + # 2/ Search invoices linked to these stock picking |
2245 | + # 3/ Take stock picking not linked to an invoice |
2246 | + # 4/ Use these non-invoiced closed stock picking to add their amount to the "invoiced" amount |
2247 | + for invoice in purchase.invoice_ids: |
2248 | + if invoice.state not in ('draft','cancel'): |
2249 | + tot += invoice.amount_untaxed |
2250 | + stock_pickings = sp_obj.search(cursor, user, [('purchase_id', '=', purchase.id), ('state', '=', 'done')]) |
2251 | + if stock_pickings: |
2252 | + sp_ids = list(stock_pickings) |
2253 | + if isinstance(stock_pickings, (int, long)): |
2254 | + stock_pickings = [stock_pickings] |
2255 | + for sp in stock_pickings: |
2256 | + inv_ids = inv_obj.search_exist(cursor, user, [('picking_id', '=', sp)]) |
2257 | + if inv_ids: |
2258 | + sp_ids.remove(sp) |
2259 | + if sp_ids: |
2260 | + for stock_picking in sp_obj.browse(cursor, user, sp_ids): |
2261 | + for line in stock_picking.move_lines: |
2262 | + tot += line.product_qty * line.price_unit |
2263 | + if purchase.amount_untaxed: |
2264 | + res[purchase.id] = min(100.0, tot * 100.0 / (purchase.amount_untaxed)) |
2265 | + else: |
2266 | + res[purchase.id] = 0.0 |
2267 | return res |
2268 | |
2269 | def _shipped_rate(self, cr, uid, ids, name, arg, context=None): |
2270 | @@ -140,61 +172,399 @@ |
2271 | result[line.order_id.id] = True |
2272 | return result.keys() |
2273 | |
2274 | + def _get_allocation_setup(self, cr, uid, ids, field_name, args, context=None): |
2275 | + ''' |
2276 | + Returns the Unifield configuration value |
2277 | + ''' |
2278 | + res = {} |
2279 | + setup = self.pool.get('unifield.setup.configuration').get_config(cr, uid) |
2280 | + |
2281 | + for order in ids: |
2282 | + res[order] = setup.allocation_setup |
2283 | + |
2284 | + return res |
2285 | + |
2286 | + def _get_no_line(self, cr, uid, ids, field_name, args, context=None): |
2287 | + """ |
2288 | + Compute the number of Purchase order lines in each purchase order. |
2289 | + A split line is count as one line |
2290 | + :param cr: Cursor to the database |
2291 | + :param uid: ID of the res.users that calls this method |
2292 | + :param ids: List of purchase.order ID to compute |
2293 | + :param field_name: Name of the field to compute |
2294 | + :param args: Extra parameters |
2295 | + :param context: Context of the call |
2296 | + :return: A dictionnary with the purchase.order ID as keys and the number of Purchase |
2297 | + order lines for each of them as value |
2298 | + """ |
2299 | + pol_obj = self.pool.get('sale.order.line') |
2300 | + |
2301 | + if context is None: |
2302 | + context = {} |
2303 | + |
2304 | + if isinstance(ids, (int, long)): |
2305 | + ids = [ids] |
2306 | + |
2307 | + res = {} |
2308 | + |
2309 | + for order_id in ids: |
2310 | + res[order_id] = pol_obj.search_count(cr, uid, [ |
2311 | + ('order_id', '=', order_id), |
2312 | + ('is_line_split', '=', False), |
2313 | + ], context=context) |
2314 | + |
2315 | + return res |
2316 | + |
2317 | + |
2318 | + def _po_from_x(self, cr, uid, ids, field_name, args, context=None): |
2319 | + """ |
2320 | + fields.function multi for 'po_from_ir' and 'po_from_fo' fields. |
2321 | + As one PO can contains lines from IR and from FO, both fields can be True |
2322 | + """ |
2323 | + if context is None: |
2324 | + context = {} |
2325 | + if isinstance(ids, (int,long)): |
2326 | + ids = [ids] |
2327 | + |
2328 | + res = {} |
2329 | + for po in self.browse(cr, uid, ids, context=context): |
2330 | + res[po.id] = { |
2331 | + 'po_from_ir': False, |
2332 | + 'po_from_fo': False, |
2333 | + } |
2334 | + |
2335 | + return res |
2336 | + |
2337 | + def _get_dest_partner_names(self, cr, uid, ids, field_name, args, context=None): |
2338 | + res = {} |
2339 | + res_partner_obj = self.pool.get('res.partner') |
2340 | + for po_r in self.read(cr, uid, ids, ['dest_partner_ids'], context=context): |
2341 | + names = '' |
2342 | + if po_r['dest_partner_ids']: |
2343 | + name_tuples = res_partner_obj.name_get(cr, uid, po_r['dest_partner_ids'], context=context) |
2344 | + if name_tuples: |
2345 | + names_list = [nt[1] for nt in name_tuples] |
2346 | + names = "; ".join(names_list) |
2347 | + res[po_r['id']] = names |
2348 | + return res |
2349 | + |
2350 | + def _get_project_ref(self, cr, uid, ids, field_name, args, context=None): |
2351 | + ''' |
2352 | + Get the name of the POs at project side |
2353 | + ''' |
2354 | + if isinstance(ids, (int, long)): |
2355 | + ids = [ids] |
2356 | + |
2357 | + res = {} |
2358 | + so_obj = self.pool.get('sale.order') |
2359 | + for po in ids: |
2360 | + res[po] = { |
2361 | + 'fnct_project_ref': '', |
2362 | + 'sourced_references': '', |
2363 | + } |
2364 | + |
2365 | + so_ids = self.get_so_ids_from_po_ids(cr, uid, po, context=context) |
2366 | + for so in so_obj.read(cr, uid, so_ids, ['client_order_ref', 'name'], context=context): |
2367 | + if so['client_order_ref']: |
2368 | + if res[po]['fnct_project_ref']: |
2369 | + res[po]['fnct_project_ref'] += ' - ' |
2370 | + res[po]['fnct_project_ref'] += so['client_order_ref'] |
2371 | + |
2372 | + if res[po]['sourced_references']: |
2373 | + res[po]['sourced_references'] += ',' |
2374 | + res[po]['sourced_references'] += so['name'] |
2375 | + |
2376 | + return res |
2377 | + |
2378 | + def _get_vat_ok(self, cr, uid, ids, field_name, args, context=None): |
2379 | + ''' |
2380 | + Return True if the system configuration VAT management is set to True |
2381 | + ''' |
2382 | + vat_ok = self.pool.get('unifield.setup.configuration').get_config(cr, uid).vat_ok |
2383 | + res = {} |
2384 | + for id in ids: |
2385 | + res[id] = vat_ok |
2386 | + |
2387 | + return res |
2388 | + |
2389 | + def _get_requested_date_in_past(self, cr, uid, ids, field_name, args, context=None): |
2390 | + if isinstance(ids, (int, long)): |
2391 | + ids = [ids] |
2392 | + |
2393 | + res = {} |
2394 | + for po in self.read(cr, uid, ids, ['delivery_requested_date', 'rfq_ok'], context=context): |
2395 | + res[po['id']] = po['delivery_requested_date'] and not po['rfq_ok'] and po['delivery_requested_date'] < time.strftime('%Y-%m-%d') or False |
2396 | + |
2397 | + return res |
2398 | + |
2399 | + |
2400 | def _invoiced(self, cursor, user, ids, name, arg, context=None): |
2401 | res = {} |
2402 | - for purchase in self.browse(cursor, user, ids, context=context): |
2403 | + for purchase in self.read(cursor, user, ids, ['invoiced_rate'], context=context): |
2404 | invoiced = False |
2405 | - if purchase.invoiced_rate == 100.00: |
2406 | + if purchase['invoiced_rate'] == 100.00: |
2407 | invoiced = True |
2408 | - res[purchase.id] = invoiced |
2409 | - return res |
2410 | - |
2411 | - STATE_SELECTION = [ |
2412 | - ('draft', 'Request for Quotation'), |
2413 | - ('wait', 'Waiting'), |
2414 | - ('confirmed', 'Waiting Approval'), |
2415 | - ('approved', 'Approved'), |
2416 | - ('except_picking', 'Shipping Exception'), |
2417 | - ('except_invoice', 'Invoice Exception'), |
2418 | - ('done', 'Done'), |
2419 | - ('cancel', 'Cancelled') |
2420 | - ] |
2421 | + res[purchase['id']] = invoiced |
2422 | + return res |
2423 | + |
2424 | + def _src_customer_ref(self, cr, uid, obj, name, args, context=None): |
2425 | + ''' |
2426 | + return a domain when user filter on the customer_ref field |
2427 | + ''' |
2428 | + if not args: |
2429 | + return [] |
2430 | + |
2431 | + po_ids = set() |
2432 | + for tu in args: |
2433 | + if tu[1] in ('ilike', 'not ilike', '=', '!='): |
2434 | + so_ids = self.pool.get('sale.order').search(cr, uid, [('client_order_ref', tu[1], tu[2])], context=context) |
2435 | + sol_ids = self.pool.get('sale.order.line').search(cr, uid, [('order_id', 'in', so_ids)], context=context) |
2436 | + pol_ids = self.pool.get('purchase.order.line').search(cr, uid, [('linked_sol_id', 'in', sol_ids)], context=context) |
2437 | + for pol in self.pool.get('purchase.order.line').browse(cr, uid, pol_ids, context=context): |
2438 | + po_ids.add(pol.order_id.id) |
2439 | + else: |
2440 | + raise osv.except_osv(_('Error'), _('Bad operator : You can only use \'=\', \'!=\', \'ilike\' or \'not ilike\' as operator')) |
2441 | + |
2442 | + return [('id', 'in', list(po_ids))] |
2443 | + |
2444 | + def _get_customer_ref(self, cr, uid, ids, field_name, args, context=None): |
2445 | + ''' |
2446 | + Return a concatenation of the PO's customer references from the project (case of procurement request) |
2447 | + ''' |
2448 | + if isinstance(ids, (int, long)): |
2449 | + ids = [ids] |
2450 | + |
2451 | + res = {} |
2452 | + so_obj = self.pool.get('sale.order') |
2453 | + for po_id in ids: |
2454 | + res[po_id] = "" |
2455 | + |
2456 | + so_ids = self.get_so_ids_from_po_ids(cr, uid, po_id, context=context) |
2457 | + for so in so_obj.read(cr, uid, so_ids, ['client_order_ref'], context=context): |
2458 | + if so['client_order_ref']: |
2459 | + if res[po_id]: |
2460 | + res[po_id] += ';' |
2461 | + res[po_id] += so['client_order_ref'] |
2462 | + |
2463 | + return res |
2464 | + |
2465 | + def _get_line_count(self, cr, uid, ids, field_name, args, context=None): |
2466 | + ''' |
2467 | + Return the number of line(s) for the PO |
2468 | + ''' |
2469 | + pol_obj = self.pool.get('purchase.order.line') |
2470 | + |
2471 | + if isinstance(ids, (int, long)): |
2472 | + ids = [ids] |
2473 | + |
2474 | + res = {}.fromkeys(ids, 0) |
2475 | + line_number_by_order = {} |
2476 | + |
2477 | + lines = pol_obj.search(cr, uid, [('order_id', 'in', ids)], context=context) |
2478 | + for l in pol_obj.read(cr, uid, lines, ['order_id', 'line_number'], context=context): |
2479 | + line_number_by_order.setdefault(l['order_id'][0], set()) |
2480 | + line_number_by_order[l['order_id'][0]].add(l['line_number']) |
2481 | + |
2482 | + for po_id, ln in line_number_by_order.iteritems(): |
2483 | + res[po_id] = len(ln) |
2484 | + |
2485 | + return res |
2486 | + |
2487 | + |
2488 | + def _get_less_advanced_pol_state(self, cr, uid, ids, field_name, arg, context=None): |
2489 | + """ |
2490 | + Get the less advanced state of the purchase order lines |
2491 | + Used to compute sale order state |
2492 | + """ |
2493 | + if context is None: |
2494 | + context = {} |
2495 | + if isinstance(ids, (int, long)): |
2496 | + ids = [ids] |
2497 | + |
2498 | + res = {} |
2499 | + for po in self.browse(cr, uid, ids, context=context): |
2500 | + pol_states = set([line.state for line in po.order_line]) |
2501 | + if all([s.startswith('cancel') for s in pol_states]): # if all lines are cancelled then the PO is cancelled |
2502 | + res[po.id] = 'cancel' |
2503 | + else: # else compute the less advanced state: |
2504 | + # cancel state must be ignored: |
2505 | + pol_states.discard('cancel') |
2506 | + pol_states.discard('cancel_r') |
2507 | + res[po.id] = self.pool.get('purchase.order.line.state').get_less_advanced_state(cr, uid, ids, pol_states, context=context) |
2508 | + |
2509 | + if res[po.id] == 'draft': # set the draft-p state ? |
2510 | + draft_sequence = self.pool.get('purchase.order.line.state').get_sequence(cr, uid, ids, 'draft', context=context) |
2511 | + # do we have a line further then draft in our FO ? |
2512 | + if any([self.pool.get('purchase.order.line.state').get_sequence(cr, uid, ids, s, context=context) > draft_sequence for s in pol_states]): |
2513 | + res[po.id] = 'draft_p' |
2514 | + elif res[po.id] in ('validated', 'validated_n'): # set the validated-p state ? |
2515 | + validated_sequence = self.pool.get('purchase.order.line.state').get_sequence(cr, uid, ids, 'validated', context=context) |
2516 | + # do we have a line further then validated in our FO ? |
2517 | + if any([self.pool.get('purchase.order.line.state').get_sequence(cr, uid, ids, s, context=context) > validated_sequence for s in pol_states]): |
2518 | + res[po.id] = 'validated_p' |
2519 | + else: |
2520 | + res[po.id] = 'validated' |
2521 | + elif res[po.id].startswith('sourced'): # set the sourced-p state ? |
2522 | + sourced_sequence = self.pool.get('purchase.order.line.state').get_sequence(cr, uid, ids, 'sourced', context=context) |
2523 | + # do we have a line further then sourced in our FO ? |
2524 | + if any([self.pool.get('purchase.order.line.state').get_sequence(cr, uid, ids, s, context=context) > sourced_sequence for s in pol_states]): |
2525 | + res[po.id] = 'sourced_p' |
2526 | + else: |
2527 | + res[po.id] = 'sourced' |
2528 | + elif res[po.id] == 'confirmed': # set the confirmed-p state ? |
2529 | + confirmed_sequence = self.pool.get('purchase.order.line.state').get_sequence(cr, uid, ids, 'confirmed', context=context) |
2530 | + # do we have a line further then confirmed in our FO ? |
2531 | + if any([self.pool.get('purchase.order.line.state').get_sequence(cr, uid, ids, s, context=context) > confirmed_sequence for s in pol_states]): |
2532 | + res[po.id] = 'confirmed_p' |
2533 | + |
2534 | + return res |
2535 | + |
2536 | + def _is_fixed_type(self, cr, uid, ids, field_name, args, context=None): |
2537 | + """ |
2538 | + For each PO, set is the Order Type of the PO can be changed or not |
2539 | + :param cr: Cursor to the database |
2540 | + :param uid: ID of the res.users that calls this method |
2541 | + :param ids: List of ID of purchase.order records to check |
2542 | + :param field_name: Name of the field to compute |
2543 | + :param args: Extra parameters |
2544 | + :param context: Context of the call |
2545 | + :return: A dictionnary with ID of the purchase.order record as keys and True/Fales as values |
2546 | + """ |
2547 | + if isinstance(ids, (int, long)): |
2548 | + ids = [ids] |
2549 | + |
2550 | + if context is None: |
2551 | + context = {} |
2552 | + |
2553 | + context['procurement_request'] = True |
2554 | + |
2555 | + res = {} |
2556 | + for po in self.browse(cr, uid, ids, fields_to_fetch=['po_from_fo', 'po_from_ir'], context=context): |
2557 | + if po.po_from_fo or po.po_from_ir: |
2558 | + src_type = set() |
2559 | + sale_ids = self.get_so_ids_from_po_ids(cr, uid, [po.id], context=context) |
2560 | + if sale_ids: |
2561 | + for sale in self.pool.get('sale.order').read(cr, uid, sale_ids, ['procurement_request', 'order_type'], context=context): |
2562 | + if sale['procurement_request'] or sale['order_type'] == 'regular': |
2563 | + src_type.add('regular') |
2564 | + src_type.add('purchase_list') |
2565 | + |
2566 | + if not sale['procurement_request']: |
2567 | + if sale['order_type'] == 'regular': |
2568 | + src_type.add('direct') |
2569 | + elif sale['order_type'] == 'loan': |
2570 | + src_type.add('loan') |
2571 | + elif sale['order_type'] == 'donation_exp': |
2572 | + src_type.add('donation_exp') |
2573 | + elif sale['order_type'] == 'donation_st': |
2574 | + src_type.add('donation_st') |
2575 | + res[po.id] = json.dumps(list(src_type)) |
2576 | + else: |
2577 | + res[po.id] = json.dumps([x[0] for x in ORDER_TYPES_SELECTION]) |
2578 | + |
2579 | + return res |
2580 | + |
2581 | + def _order_line_order_type(self, cr, uid, ids, context=None): |
2582 | + """ |
2583 | + Return the list of ID of purchase.order records to update |
2584 | + :param cr: Cursor to the database |
2585 | + :param uid: ID of the res.users that calls this method |
2586 | + :param ids: List of ID of purchase.order.line records updated |
2587 | + :param context: Context of the call |
2588 | + :return: A list that represents a domain to apply on purchase.order records |
2589 | + """ |
2590 | + lines = self.read(cr, uid, ids, ['order_id'], context=context) |
2591 | + po_ids = set() |
2592 | + for l in lines: |
2593 | + po_ids.add(l['order_id'][0]) |
2594 | + |
2595 | + return list(po_ids) |
2596 | + |
2597 | |
2598 | _columns = { |
2599 | - 'name': fields.char('Order Reference', size=64, required=True, select=True, help="unique number of the purchase order,computed automatically when the purchase order is created"), |
2600 | - 'origin': fields.char('Source Document', size=512, |
2601 | - help="Reference of the document that generated this purchase order request." |
2602 | - ), |
2603 | - 'partner_ref': fields.char('Supplier Reference', states={'confirmed':[('readonly',True)], 'approved':[('readonly',True)],'done':[('readonly',True)]}, size=64), |
2604 | - 'date_order':fields.date('Date Ordered', required=True, states={'confirmed':[('readonly',True)], 'approved':[('readonly',True)]}, select=True, help="Date on which this document has been created."), |
2605 | + 'order_type': fields.selection(ORDER_TYPES_SELECTION, string='Order Type', required=True, states={'sourced':[('readonly',True)], 'split':[('readonly',True)], 'approved':[('readonly',True)],'done':[('readonly',True)]}), |
2606 | + 'loan_id': fields.many2one('sale.order', string='Linked loan', readonly=True), |
2607 | + 'priority': fields.selection(ORDER_PRIORITY, string='Priority', states={'approved':[('readonly',True)],'done':[('readonly',True)]}), |
2608 | + 'categ': fields.selection(ORDER_CATEGORY, string='Order category', required=True, states={'approved':[('readonly',True)],'done':[('readonly',True)]}), |
2609 | + # we increase the size of the 'details' field from 30 to 86 |
2610 | + 'details': fields.char(size=86, string='Details', states={'sourced':[('readonly',True)], 'split':[('readonly',True)], 'cancel':[('readonly',True)], 'confirmed_wait':[('readonly',True)], 'validated':[('readonly',True)], 'approved':[('readonly',True)],'done':[('readonly',True)]}), |
2611 | + 'loan_duration': fields.integer(string='Loan duration', help='Loan duration in months', states={'validated':[('readonly',True)],'approved':[('readonly',True)],'done':[('readonly',True)]}), |
2612 | + 'date_order': fields.date(string='Creation Date', readonly=True, required=True, |
2613 | + states={'draft':[('readonly',False)],}, select=True, help="Date on which this document has been created."), |
2614 | + 'name': fields.char('Order Reference', size=64, required=True, select=True, readonly=True, |
2615 | + help="unique number of the purchase order,computed automatically when the purchase order is created"), |
2616 | + 'invoice_ids': fields.many2many('account.invoice', 'purchase_invoice_rel', 'purchase_id', 'invoice_id', 'Invoices', help="Invoices generated for a purchase order", readonly=True), |
2617 | + 'order_line': fields.one2many('purchase.order.line', 'order_id', 'Order Lines', readonly=True, states={'draft':[('readonly',False)], 'validated': [('readonly',False)]}), |
2618 | + 'partner_id': fields.many2one('res.partner', 'Supplier', required=True, states={'sourced':[('readonly',True)], 'split':[('readonly',True)], 'rfq_sent':[('readonly',True)], 'rfq_done':[('readonly',True)], 'rfq_updated':[('readonly',True)], 'confirmed':[('readonly',True)], 'confirmed_wait':[('readonly',True)], 'approved':[('readonly',True)],'done':[('readonly',True)],'cancel':[('readonly',True)]}, change_default=True, domain="[('id', '!=', company_id)]"), |
2619 | + 'partner_address_id': fields.many2one('res.partner.address', 'Address', required=True, |
2620 | + states={'sourced':[('readonly',True)], 'split':[('readonly',True)], 'rfq_sent':[('readonly',True)], 'rfq_done':[('readonly',True)], 'rfq_updated':[('readonly',True)], 'validated':[('readonly',True)], 'approved':[('readonly',True)],'done':[('readonly',True)]},domain="[('partner_id', '=', partner_id)]"), |
2621 | + 'dest_partner_id': fields.many2one('res.partner', string='Destination partner'), |
2622 | + 'invoice_address_id': fields.many2one('res.partner.address', string='Invoicing address', required=True, |
2623 | + help="The address where the invoice will be sent."), |
2624 | + 'invoice_method': fields.selection([('manual','Manual'),('order','From Order'),('picking','From Picking')], 'Invoicing Control', required=True, readonly=True, |
2625 | + help="From Order: a draft invoice will be pre-generated based on the purchase order. The accountant " \ |
2626 | + "will just have to validate this invoice for control.\n" \ |
2627 | + "From Picking: a draft invoice will be pre-generated based on validated receptions.\n" \ |
2628 | + "Manual: allows you to generate suppliers invoices by chosing in the uninvoiced lines of all manual purchase orders." |
2629 | + ), |
2630 | + 'merged_line_ids': fields.one2many('purchase.order.merged.line', 'order_id', string='Merged line'), |
2631 | + 'date_confirm': fields.date(string='Confirmation date'), |
2632 | + 'allocation_setup': fields.function(_get_allocation_setup, type='selection', |
2633 | + selection=[('allocated', 'Allocated'), |
2634 | + ('unallocated', 'Unallocated'), |
2635 | + ('mixed', 'Mixed')], string='Allocated setup', method=True, store=False), |
2636 | + 'unallocation_ok': fields.boolean(string='Unallocated PO'), |
2637 | + 'partner_ref': fields.char('Supplier Reference', size=128), |
2638 | + 'product_id': fields.related('order_line', 'product_id', type='many2one', relation='product.product', string='Product'), |
2639 | + 'no_line': fields.function(_get_no_line, method=True, type='boolean', string='No line'), |
2640 | + 'active': fields.boolean('Active', readonly=True), |
2641 | + 'po_from_ir': fields.function(_po_from_x, method=True, type='boolean', string='Is PO from IR ?', multi='po_from_x'), |
2642 | + 'po_from_fo': fields.function(_po_from_x, method=True, type='boolean', string='Is PO from FO ?', multi='po_from_x'), |
2643 | + 'canceled_end': fields.boolean(string='Canceled End', readonly=True), |
2644 | + 'is_a_counterpart': fields.boolean('Counterpart?', help="This field is only for indicating that the order is a counterpart"), |
2645 | + 'po_updated_by_sync': fields.boolean('PO updated by sync', readonly=False), |
2646 | + 'origin': fields.text('Source Document', help="Reference of the document that generated this purchase order request."), |
2647 | + # UF-2267: Store also the parent PO as reference in the sourced PO |
2648 | + 'parent_order_name': fields.many2one('purchase.order', string='Parent PO name', help='If the PO is created from a re-source FO, this field contains the relevant original PO name'), |
2649 | + 'project_ref': fields.char(size=256, string='Project Ref.'), |
2650 | + 'message_esc': fields.text(string='ESC Message'), |
2651 | + 'fnct_project_ref': fields.function(_get_project_ref, method=True, string='Project Ref.', |
2652 | + type='char', size=256, store=False, multi='so_info'), |
2653 | + 'dest_partner_ids': fields.many2many('res.partner', 'res_partner_purchase_order_rel', 'purchase_order_id', 'partner_id', 'Customers'), # uf-2223 |
2654 | + 'dest_partner_names': fields.function(_get_dest_partner_names, type='char', size=256, string='Customers', method=True), # uf-2223 |
2655 | + 'split_po': fields.boolean('Created by split PO', readonly=True), |
2656 | + 'sourced_references': fields.function(_get_project_ref, method=True, string='Sourced references', type='text', store=False, multi='so_info'), |
2657 | + 'vat_ok': fields.function(_get_vat_ok, method=True, type='boolean', string='VAT OK', store=False, readonly=True), |
2658 | + 'requested_date_in_past': fields.function(_get_requested_date_in_past, method=True, string='Requested date in past', type='boolean', store=False), |
2659 | + 'update_in_progress': fields.boolean(string='Update in progress', readonly=True), |
2660 | + # US-1765: register the 1st call of wkf_confirm_trigger to prevent recursion error |
2661 | + 'po_confirmed': fields.boolean('PO', readonly=True), |
2662 | + 'customer_ref': fields.function(_get_customer_ref, fnct_search=_src_customer_ref, method=True, string='Customer Ref.', type='text', store=False), |
2663 | + 'line_count': fields.function(_get_line_count, method=True, type='integer', string="Line count", store=False), |
2664 | + |
2665 | 'date_approve':fields.date('Date Approved', readonly=1, select=True, help="Date on which purchase order has been approved"), |
2666 | - 'partner_id':fields.many2one('res.partner', 'Supplier', required=True, states={'confirmed':[('readonly',True)], 'approved':[('readonly',True)],'done':[('readonly',True)]}, change_default=True), |
2667 | - 'partner_address_id':fields.many2one('res.partner.address', 'Address', required=True, |
2668 | - states={'confirmed':[('readonly',True)], 'approved':[('readonly',True)],'done':[('readonly',True)]},domain="[('partner_id', '=', partner_id)]"), |
2669 | 'dest_address_id':fields.many2one('res.partner.address', 'Destination Address', |
2670 | - states={'confirmed':[('readonly',True)], 'approved':[('readonly',True)],'done':[('readonly',True)]}, |
2671 | + states={'validated':[('readonly',True)], 'approved':[('readonly',True)],'done':[('readonly',True)]}, |
2672 | help="Put an address if you want to deliver directly from the supplier to the customer." \ |
2673 | "In this case, it will remove the warehouse link and set the customer location." |
2674 | ), |
2675 | - 'warehouse_id': fields.many2one('stock.warehouse', 'Warehouse', states={'confirmed':[('readonly',True)], 'approved':[('readonly',True)],'done':[('readonly',True)]}), |
2676 | + 'warehouse_id': fields.many2one('stock.warehouse', 'Warehouse', states={'validated':[('readonly',True)], 'approved':[('readonly',True)],'done':[('readonly',True)]}), |
2677 | 'location_id': fields.many2one('stock.location', 'Destination', required=True, domain=[('usage','<>','view')]), |
2678 | - 'pricelist_id':fields.many2one('product.pricelist', 'Pricelist', required=True, states={'confirmed':[('readonly',True)], 'approved':[('readonly',True)],'done':[('readonly',True)]}, help="The pricelist sets the currency used for this purchase order. It also computes the supplier price for the selected products/quantities."), |
2679 | - 'state': fields.selection(STATE_SELECTION, 'State', readonly=True, help="The state of the purchase order or the quotation request. A quotation is a purchase order in a 'Draft' state. Then the order has to be confirmed by the user, the state switch to 'Confirmed'. Then the supplier must confirm the order to change the state to 'Approved'. When the purchase order is paid and received, the state becomes 'Done'. If a cancel action occurs in the invoice or in the reception of goods, the state becomes in exception.", select=True), |
2680 | - 'order_line': fields.one2many('purchase.order.line', 'order_id', 'Order Lines', states={'approved':[('readonly',True)],'done':[('readonly',True)]}), |
2681 | + 'pricelist_id': fields.many2one('product.pricelist', 'Pricelist', required=True, states={'validated':[('readonly',True)], 'approved':[('readonly',True)],'done':[('readonly',True)]}, help="The pricelist sets the currency used for this purchase order. It also computes the supplier price for the selected products/quantities."), |
2682 | + 'state': fields.function(_get_less_advanced_pol_state, string='Order State', method=True, type='selection', selection=PURCHASE_ORDER_STATE_SELECTION, readonly=True, |
2683 | + store = { |
2684 | + 'purchase.order.line': (_get_order, ['state'], 10), |
2685 | + }, |
2686 | + select=True, help="The state of the purchase order or the quotation request. A quotation is a purchase order in a 'Draft' state. Then the order has to be confirmed by the user, the state switch to 'Confirmed'. Then the supplier must confirm the order to change the state to 'Approved'. When the purchase order is paid and received, the state becomes 'Done'. If a cancel action occurs in the invoice or in the reception of goods, the state becomes in exception." |
2687 | + ), |
2688 | + |
2689 | 'validator' : fields.many2one('res.users', 'Validated by', readonly=True), |
2690 | 'notes': fields.text('Notes'), |
2691 | - 'invoice_ids': fields.many2many('account.invoice', 'purchase_invoice_rel', 'purchase_id', 'invoice_id', 'Invoices', help="Invoices generated for a purchase order"), |
2692 | 'picking_ids': fields.one2many('stock.picking', 'purchase_id', 'Picking List', readonly=True, help="This is the list of picking list that have been generated for this purchase"), |
2693 | 'shipped':fields.boolean('Received', readonly=True, select=True, help="It indicates that a picking has been done"), |
2694 | 'shipped_rate': fields.function(_shipped_rate, method=True, string='Received', type='float'), |
2695 | - 'invoiced': fields.function(_invoiced, method=True, string='Invoiced & Paid', type='boolean', help="It indicates that an invoice has been paid"), |
2696 | + 'invoiced': fields.function(_invoiced, method=True, string='Invoiced', type='boolean', help="It indicates that an invoice has been generated"), |
2697 | 'invoiced_rate': fields.function(_invoiced_rate, method=True, string='Invoiced', type='float'), |
2698 | - 'invoice_method': fields.selection([('manual','Manual'),('order','From Order'),('picking','From Picking')], 'Invoicing Control', required=True, |
2699 | - help="From Order: a draft invoice will be pre-generated based on the purchase order. The accountant " \ |
2700 | - "will just have to validate this invoice for control.\n" \ |
2701 | - "From Picking: a draft invoice will be pre-generated based on validated receptions.\n" \ |
2702 | - "Manual: allows you to generate suppliers invoices by chosing in the uninvoiced lines of all manual purchase orders." |
2703 | - ), |
2704 | 'minimum_planned_date':fields.function(_minimum_planned_date, fnct_inv=_set_minimum_planned_date, method=True, string='Expected Date', type='date', select=True, help="This is computed as the minimum scheduled date of all purchase order lines' products.", |
2705 | store = { |
2706 | 'purchase.order.line': (_get_order, ['date_planned'], 10), |
2707 | @@ -213,37 +583,188 @@ |
2708 | 'purchase.order.line': (_get_order, ['price_subtotal', 'taxes_id', 'price_unit', 'product_qty', 'product_id'], 10), |
2709 | }, multi="sums",help="The total amount"), |
2710 | 'fiscal_position': fields.many2one('account.fiscal.position', 'Fiscal Position'), |
2711 | - 'product_id': fields.related('order_line','product_id', type='many2one', relation='product.product', string='Product'), |
2712 | 'create_uid': fields.many2one('res.users', 'Responsible'), |
2713 | 'company_id': fields.many2one('res.company','Company',required=True,select=1), |
2714 | 'stock_take_date': fields.date(string='Date of Stock Take', required=False), |
2715 | + 'fixed_order_type': fields.function(_is_fixed_type, method=True, type='char', size=256, string='Possible order types', store={ |
2716 | + 'purchase.order': (lambda obj, cr, uid, ids, c={}: ids, ['order_line'], 10), |
2717 | + 'purchase.order.line': (_order_line_order_type, ['order_id'], 10), |
2718 | + }, |
2719 | + ), |
2720 | } |
2721 | _defaults = { |
2722 | + 'po_confirmed': lambda *a: False, |
2723 | + 'order_type': lambda *a: 'regular', |
2724 | + 'priority': lambda *a: 'normal', |
2725 | + 'categ': lambda *a: 'other', |
2726 | + 'loan_duration': 2, |
2727 | + 'invoice_address_id': lambda obj, cr, uid, ctx: obj.pool.get('res.partner').address_get(cr, uid, obj.pool.get('res.users').browse(cr, uid, uid, ctx).company_id.partner_id.id, ['invoice'])['invoice'], |
2728 | + 'invoice_method': lambda *a: 'picking', |
2729 | + 'dest_address_id': lambda obj, cr, uid, ctx: obj.pool.get('res.partner').address_get(cr, uid, obj.pool.get('res.users').browse(cr, uid, uid, ctx).company_id.partner_id.id, ['delivery'])['delivery'], |
2730 | + 'no_line': lambda *a: True, |
2731 | + 'active': True, |
2732 | + 'name': lambda *a: False, |
2733 | + 'is_a_counterpart': False, |
2734 | + 'parent_order_name': False, |
2735 | + 'canceled_end': False, |
2736 | + 'split_po': False, |
2737 | + 'vat_ok': lambda obj, cr, uid, context: obj.pool.get('unifield.setup.configuration').get_config(cr, uid).vat_ok, |
2738 | + 'update_in_progress': False, |
2739 | 'date_order': lambda *a: time.strftime('%Y-%m-%d'), |
2740 | 'state': 'draft', |
2741 | - 'name': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'purchase.order'), |
2742 | 'shipped': 0, |
2743 | - 'invoice_method': 'order', |
2744 | 'invoiced': 0, |
2745 | 'partner_address_id': lambda self, cr, uid, context: context.get('partner_id', False) and self.pool.get('res.partner').address_get(cr, uid, [context['partner_id']], ['default'])['default'], |
2746 | 'pricelist_id': lambda self, cr, uid, context: context.get('partner_id', False) and self.pool.get('res.partner').browse(cr, uid, context['partner_id']).property_product_pricelist_purchase.id, |
2747 | 'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'purchase.order', context=c), |
2748 | + 'fixed_order_type': lambda *a: json.dumps([]), |
2749 | } |
2750 | _sql_constraints = [ |
2751 | ('name_uniq', 'unique(name)', 'Order Reference must be unique !'), |
2752 | ] |
2753 | - _name = "purchase.order" |
2754 | - _description = "Purchase Order" |
2755 | - _order = "name desc" |
2756 | + |
2757 | + def _check_po_from_fo(self, cr, uid, ids, context=None): |
2758 | + if not context: |
2759 | + context = {} |
2760 | + for po in self.browse(cr, uid, ids, context=context): |
2761 | + if po.partner_id.partner_type == 'internal' and po.po_from_fo: |
2762 | + return False |
2763 | + return True |
2764 | + |
2765 | + def _check_order_type(self, cr, uid, ids, context=None): |
2766 | + ''' |
2767 | + Check the integrity of the order type and the source order type |
2768 | + :param cr: Cursor to the database |
2769 | + :param uid: ID of the res.users that calls this method |
2770 | + :param ids: List of ID of sale.order to check |
2771 | + :param context: Context of the call |
2772 | + :return: True if the integrity is ok. |
2773 | + ''' |
2774 | + err = [] |
2775 | + |
2776 | + order_types_dict = dict((x, y) for x, y in ORDER_TYPES_SELECTION) |
2777 | + |
2778 | + for order in self.read(cr, uid, ids, ['name', 'fixed_order_type', 'order_type', 'is_a_counterpart'], context=context): |
2779 | + if order['is_a_counterpart'] and order['order_type'] != 'loan': |
2780 | + err.append(_('%s: This purchase order is a loan counterpart. You cannot change its order type') % order['name']) |
2781 | + else: |
2782 | + json_info = json.loads(order['fixed_order_type']) |
2783 | + if json_info and order['order_type'] not in json_info: |
2784 | + allowed_type = ' / '.join(order_types_dict.get(x) for x in json_info) |
2785 | + err.append(_('%s: Only %s order types are allowed for this purchase order') % (order['name'], allowed_type)) |
2786 | + |
2787 | + if err: |
2788 | + raise osv.except_osv( |
2789 | + _('Error'), |
2790 | + '\n'.join(x for x in err), |
2791 | + ) |
2792 | + |
2793 | + return True |
2794 | + |
2795 | + _constraints = [ |
2796 | + (_check_po_from_fo, 'You cannot choose an internal supplier for this purchase order', []), |
2797 | + (_check_order_type, 'The order type of the order is not consistent with the order type of the source', ['order_type']) |
2798 | + ] |
2799 | + |
2800 | + def default_get(self, cr, uid, fields, context=None): |
2801 | + ''' |
2802 | + Fill the unallocated_ok field according to Unifield setup |
2803 | + ''' |
2804 | + res = super(purchase_order, self).default_get(cr, uid, fields, context=context) |
2805 | + |
2806 | + setup = self.pool.get('unifield.setup.configuration').get_config(cr, uid) |
2807 | + res.update({'unallocation_ok': False, 'allocation_setup': setup.allocation_setup}) |
2808 | + if setup.allocation_setup == 'unallocated': |
2809 | + res.update({'unallocation_ok': True}) |
2810 | + |
2811 | + res.update({'name': False}) |
2812 | + |
2813 | + return res |
2814 | + |
2815 | + def create(self, cr, uid, vals, context=None): |
2816 | + """ |
2817 | + Filled in 'from_yml_test' to True if we come from tests |
2818 | + # UTP-114 demands purchase_list PO to be 'from picking'. |
2819 | + """ |
2820 | + if not context: |
2821 | + context = {} |
2822 | + |
2823 | + if vals.get('order_type'): |
2824 | + if vals.get('order_type') in ['donation_exp', 'donation_st']: |
2825 | + vals.update({'invoice_method': vals.get('partner_type', '') == 'section' and 'picking' or 'manual'}) |
2826 | + elif vals.get('order_type') == 'loan': |
2827 | + vals.update({'invoice_method': 'manual'}) |
2828 | + elif vals.get('order_type') in ['direct']: |
2829 | + vals.update({'invoice_method': 'order'}) |
2830 | + if vals.get('partner_id'): |
2831 | + if self.pool.get('res.partner').read(cr, uid, vals.get('partner_id'), ['partner_type'], context=context)['partner_type'] == 'esc': |
2832 | + vals.update({'invoice_method': 'manual'}) |
2833 | + else: |
2834 | + vals.update({'invoice_method': 'picking'}) |
2835 | + |
2836 | + if 'partner_id' in vals: |
2837 | + self._check_user_company(cr, uid, vals['partner_id'], context=context) |
2838 | + # we need to update the location_id because it is readonly and so does not pass in the vals of create and write |
2839 | + vals = self._get_location_id(cr, uid, vals, warehouse_id=vals.get('warehouse_id', False), context=context) |
2840 | + res = super(purchase_order, self).create(cr, uid, vals, context=context) |
2841 | + return res |
2842 | + |
2843 | + def write(self, cr, uid, ids, vals, context=None): |
2844 | + ''' |
2845 | + Check if the partner is correct. |
2846 | + # UTP-114 demand purchase_list PO to be "from picking" as invoice_method |
2847 | + ''' |
2848 | + if not ids: |
2849 | + return True |
2850 | + if 'partner_id' in vals: |
2851 | + self._check_user_company(cr, uid, vals['partner_id'], context=context) |
2852 | + |
2853 | + |
2854 | + res_partner_obj = self.pool.get('res.partner') |
2855 | + for order in self.read(cr, uid, ids, ['partner_id', 'warehouse_id'], context=context): |
2856 | + partner_type = res_partner_obj.read(cr, uid, int(vals.get('partner_id', order['partner_id'][0])), ['partner_type'], context=context)['partner_type'] |
2857 | + if vals.get('order_type'): |
2858 | + if vals.get('order_type') in ['donation_exp', 'donation_st']: |
2859 | + vals.update({'invoice_method': partner_type == 'section' and 'picking' or 'manual'}) |
2860 | + elif vals.get('order_type') == 'loan': |
2861 | + vals.update({'invoice_method': 'manual'}) |
2862 | + elif vals.get('order_type') in ['direct',] and partner_type != 'esc': |
2863 | + vals.update({'invoice_method': 'order'}) |
2864 | + elif vals.get('order_type') in ['direct',] and partner_type == 'esc': |
2865 | + vals.update({'invoice_method': 'manual'}) |
2866 | + else: |
2867 | + vals.update({'invoice_method': 'picking'}) |
2868 | + # we need to update the location_id because it is readonly and so does not pass in the vals of create and write |
2869 | + vals = self._get_location_id(cr, uid, vals, warehouse_id=vals.get('warehouse_id', order['warehouse_id'] and order['warehouse_id'][0] or False), context=context) |
2870 | + # FIXME here it is useless to continue as the next loop will |
2871 | + # overwrite vals |
2872 | + break |
2873 | + |
2874 | + # Fix bug invalid syntax for type date: |
2875 | + if 'valid_till' in vals and vals['valid_till'] == '': |
2876 | + vals['valid_till'] = False |
2877 | + |
2878 | + res = super(purchase_order, self).write(cr, uid, ids, vals, context=context) |
2879 | + |
2880 | + # Delete expected sale order line |
2881 | + if 'state' in vals and vals.get('state') not in ('draft', 'validated'): |
2882 | + exp_sol_ids = self.pool.get('expected.sale.order.line').search(cr, |
2883 | + uid, [('po_id', 'in', ids)], order='NO_ORDER', context=context) |
2884 | + self.pool.get('expected.sale.order.line').unlink(cr, uid, exp_sol_ids, context=context) |
2885 | + |
2886 | + return res |
2887 | |
2888 | def unlink(self, cr, uid, ids, context=None): |
2889 | + if self.get_so_ids_from_po_ids(cr, uid, ids, context=context): |
2890 | + raise osv.except_osv(_('Error'), _('You cannot remove a Purchase order that is linked to a Field Order or an Internal Request. Please cancel it instead.')) |
2891 | + |
2892 | purchase_orders = self.read(cr, uid, ids, ['state'], context=context) |
2893 | unlink_ids = [] |
2894 | for s in purchase_orders: |
2895 | if s['state'] in ['draft','cancel']: |
2896 | unlink_ids.append(s['id']) |
2897 | else: |
2898 | - raise osv.except_osv(_('Invalid action !'), _('Cannot delete Purchase Order(s) which are in %s State!') % _(dict(purchase_order.STATE_SELECTION).get(s['state']))) |
2899 | + raise osv.except_osv(_('Invalid action !'), _('Cannot delete Purchase Order(s) which are in %s State!') % _(dict(PURCHASE_ORDER_STATE_SELECTION).get(s['state']))) |
2900 | |
2901 | # TODO: temporary fix in 5.0, to remove in 5.2 when subflows support |
2902 | # automatically sending subflow.delete upon deletion |
2903 | @@ -257,105 +778,45 @@ |
2904 | |
2905 | return super(purchase_order, self).unlink(cr, uid, unlink_ids, context=context) |
2906 | |
2907 | - def button_dummy(self, cr, uid, ids, context=None): |
2908 | - return True |
2909 | - |
2910 | - def onchange_dest_address_id(self, cr, uid, ids, adr_id): |
2911 | - if not adr_id: |
2912 | - return {} |
2913 | - values = {'warehouse_id': False} |
2914 | - part_id = self.pool.get('res.partner.address').browse(cr, uid, adr_id).partner_id |
2915 | - if part_id: |
2916 | - loc_id = part_id.property_stock_customer.id |
2917 | - values.update({'location_id': loc_id}) |
2918 | - return {'value':values} |
2919 | - |
2920 | - def onchange_warehouse_id(self, cr, uid, ids, warehouse_id): |
2921 | - if not warehouse_id: |
2922 | - return {} |
2923 | - res = self.pool.get('stock.warehouse').read(cr, uid, [warehouse_id], ['lot_input_id'])[0]['lot_input_id'][0] |
2924 | - return {'value':{'location_id': res, 'dest_address_id': False}} |
2925 | - |
2926 | - def onchange_partner_id(self, cr, uid, ids, part): |
2927 | - |
2928 | - if not part: |
2929 | - return {'value':{'partner_address_id': False, 'fiscal_position': False}} |
2930 | - addr = self.pool.get('res.partner').address_get(cr, uid, [part], ['default']) |
2931 | - part = self.pool.get('res.partner').browse(cr, uid, part) |
2932 | - pricelist = part.property_product_pricelist_purchase.id |
2933 | - fiscal_position = part.property_account_position and part.property_account_position.id or False |
2934 | - return {'value':{'partner_address_id': addr['default'], 'pricelist_id': pricelist, 'fiscal_position': fiscal_position}} |
2935 | - |
2936 | - def wkf_approve_order(self, cr, uid, ids, context=None): |
2937 | - self.write(cr, uid, ids, {'state': 'approved', 'date_approve': time.strftime('%Y-%m-%d')}) |
2938 | - return True |
2939 | - |
2940 | - def _hook_confirm_order_message(self, cr, uid, context=None, *args, **kwargs): |
2941 | - ''' |
2942 | - Add a hook to modify the logged message |
2943 | - ''' |
2944 | - # Some verifications |
2945 | - if context is None: |
2946 | - context = {} |
2947 | - |
2948 | - return kwargs['message'] |
2949 | - |
2950 | - def _hook_confirm_order_update_corresponding_so(self, cr, uid, ids, context=None, *args, **kwargs): |
2951 | - ''' |
2952 | - Please copy this to your module's method also. |
2953 | - This hook belongs to the wkf_confirm_order method from purchase>purchase.py>purchase_order |
2954 | - |
2955 | - - allow to execute code in order to update corresponding sale order lines and sale orders if exist |
2956 | - ''' |
2957 | - # Some verifications |
2958 | - if context is None: |
2959 | - context = {} |
2960 | - if isinstance(ids, (int, long)): |
2961 | - ids = [ids] |
2962 | - |
2963 | - return True |
2964 | - |
2965 | - #UTP-872: extracted this method for a particularly check with sync |
2966 | - def _hook_check_po_no_line(self, po, context): |
2967 | - if not po.order_line: |
2968 | - raise osv.except_osv(_('Error !'), _('You can not confirm purchase order without Purchase Order Lines.')) |
2969 | - |
2970 | - def wkf_confirm_order(self, cr, uid, ids, context=None): |
2971 | - todo = [] |
2972 | - for po in self.browse(cr, uid, ids, context=context): |
2973 | - self._hook_check_po_no_line(po, context) |
2974 | - for line in po.order_line: |
2975 | - if line.state=='draft': |
2976 | - todo.append(line.id) |
2977 | - message = _("Purchase order '%s' is confirmed.") % (po.name,) |
2978 | - message = self._hook_confirm_order_message(cr, uid, context=context, message=message, po=po) |
2979 | - self.log(cr, uid, po.id, message) |
2980 | - # hook for corresponding Fo update |
2981 | - self._hook_confirm_order_update_corresponding_so(cr, uid, ids, context=context, po=po) |
2982 | -# current_name = self.name_get(cr, uid, ids)[0][1] |
2983 | - self.pool.get('purchase.order.line').action_confirm(cr, uid, todo, context) |
2984 | - for id in ids: |
2985 | - self.write(cr, uid, [id], {'state' : 'confirmed', 'validator' : uid}) |
2986 | - return True |
2987 | - |
2988 | - def wkf_warn_buyer(self, cr, uid, ids): |
2989 | - self.write(cr, uid, ids, {'state' : 'wait', 'validator' : uid}) |
2990 | - request = pooler.get_pool(cr.dbname).get('res.request') |
2991 | - for po in self.browse(cr, uid, ids): |
2992 | - managers = [] |
2993 | - for oline in po.order_line: |
2994 | - manager = oline.product_id.product_manager |
2995 | - if manager and not (manager.id in managers): |
2996 | - managers.append(manager.id) |
2997 | - for manager_id in managers: |
2998 | - request.create(cr, uid,{ |
2999 | - 'name' : _("Purchase amount over the limit"), |
3000 | - 'act_from' : uid, |
3001 | - 'act_to' : manager_id, |
3002 | - 'body': _('Somebody has just confirmed a purchase with an amount over the defined limit'), |
3003 | - 'ref_partner_id': po.partner_id.id, |
3004 | - 'ref_doc1': 'purchase.order,%d' % (po.id,), |
3005 | - }) |
3006 | + def _hook_copy_name(self, cr, uid, ids, context=None, *args, **kwargs): |
3007 | + ''' |
3008 | + HOOK from purchase>purchase.py for COPY function. Modification of default copy values |
3009 | + define which name value will be used |
3010 | + ''' |
3011 | + return {'state':'draft', |
3012 | + 'shipped':False, |
3013 | + 'invoiced':False, |
3014 | + 'invoice_ids': [], |
3015 | + 'picking_ids': [], |
3016 | + 'name': self.pool.get('ir.sequence').get(cr, uid, 'purchase.order'), |
3017 | + } |
3018 | + |
3019 | + |
3020 | + def copy(self, cr, uid, p_id, default=None, context=None): |
3021 | + ''' |
3022 | + Remove loan_id field on new purchase.order |
3023 | + ''' |
3024 | + if not default: |
3025 | + default = {} |
3026 | + if context is None: |
3027 | + context = {} |
3028 | + |
3029 | + update_values = self._hook_copy_name(cr, uid, [p_id], context=context, default=default) |
3030 | + default.update(update_values) |
3031 | + # if the copy comes from the button duplicate |
3032 | + if context.get('from_button'): |
3033 | + default.update({'is_a_counterpart': False}) |
3034 | + default.update({'loan_id': False, 'merged_line_ids': False, 'partner_ref': False, 'po_confirmed': False}) |
3035 | + if not context.get('keepOrigin', False): |
3036 | + default.update({'origin': False}) |
3037 | + |
3038 | + if not 'date_confirm' in default: |
3039 | + default['date_confirm'] = False |
3040 | + if not default.get('related_sourcing_id', False): |
3041 | + default['related_sourcing_id'] = False |
3042 | + |
3043 | + return super(purchase_order, self).copy(cr, uid, p_id, default, context=context) |
3044 | + |
3045 | def inv_line_create(self, cr, uid, a, ol): |
3046 | return (0, False, { |
3047 | 'name': ol.name, |
3048 | @@ -368,20 +829,6 @@ |
3049 | 'account_analytic_id': ol.account_analytic_id.id or False, |
3050 | }) |
3051 | |
3052 | - def action_cancel_draft(self, cr, uid, ids, *args): |
3053 | - if not len(ids): |
3054 | - return False |
3055 | - self.write(cr, uid, ids, {'state':'draft','shipped':0}) |
3056 | - wf_service = netsvc.LocalService("workflow") |
3057 | - for p_id in ids: |
3058 | - # Deleting the existing instance of workflow for PO |
3059 | - wf_service.trg_delete(uid, 'purchase.order', p_id, cr) |
3060 | - wf_service.trg_create(uid, 'purchase.order', p_id, cr) |
3061 | - for (id,name) in self.name_get(cr, uid, ids): |
3062 | - message = _("Purchase order '%s' has been set in draft state.") % name |
3063 | - self.log(cr, uid, id, message) |
3064 | - return True |
3065 | - |
3066 | def action_invoice_create(self, cr, uid, ids, *args): |
3067 | res = False |
3068 | |
3069 | @@ -425,6 +872,15 @@ |
3070 | 'payment_term': o.partner_id.property_payment_term and o.partner_id.property_payment_term.id or False, |
3071 | 'company_id': o.company_id.id, |
3072 | } |
3073 | + if o.order_type == 'purchase_list': |
3074 | + inv['purchase_list'] = 1 |
3075 | + elif o.order_type == 'in_kind': |
3076 | + inkind_journal_ids = self.pool.get('account.journal').search(cr, uid, [('type', '=', 'inkind'), ('is_current_instance', '=', True)]) |
3077 | + if not inkind_journal_ids: |
3078 | + raise osv.except_osv(_('Error'), _('No In-kind Donation journal found!')) |
3079 | + inv['journal_id'] = inkind_journal_ids[0] |
3080 | + inv['is_inkind_donation'] = True |
3081 | + |
3082 | inv_id = self.pool.get('account.invoice').create(cr, uid, inv, {'type':'in_invoice', 'journal_type': 'purchase'}) |
3083 | self.pool.get('account.invoice').button_compute(cr, uid, [inv_id], {'type':'in_invoice'}, set_total=True) |
3084 | self.pool.get('purchase.order.line').write(cr, uid, todo, {'invoiced':True}) |
3085 | @@ -432,120 +888,78 @@ |
3086 | res = inv_id |
3087 | return res |
3088 | |
3089 | - def has_stockable_product(self,cr, uid, ids, *args): |
3090 | - for order in self.browse(cr, uid, ids): |
3091 | - for order_line in order.order_line: |
3092 | - if order_line.product_id and order_line.product_id.product_tmpl_id.type in ('product', 'consu'): |
3093 | - return True |
3094 | - return False |
3095 | - |
3096 | - def action_cancel(self, cr, uid, ids, context=None): |
3097 | - for purchase in self.browse(cr, uid, ids, context=context): |
3098 | - for pick in purchase.picking_ids: |
3099 | - if pick.state not in ('draft','cancel'): |
3100 | - raise osv.except_osv( |
3101 | - _('Could not cancel purchase order !'), |
3102 | - _('You must first cancel all picking attached to this purchase order.')) |
3103 | - for pick in purchase.picking_ids: |
3104 | - wf_service = netsvc.LocalService("workflow") |
3105 | - wf_service.trg_validate(uid, 'stock.picking', pick.id, 'button_cancel', cr) |
3106 | - for inv in purchase.invoice_ids: |
3107 | - if inv and inv.state not in ('cancel','draft'): |
3108 | - raise osv.except_osv( |
3109 | - _('Could not cancel this purchase order !'), |
3110 | - _('You must first cancel all invoices attached to this purchase order.')) |
3111 | - if inv: |
3112 | - wf_service = netsvc.LocalService("workflow") |
3113 | - wf_service.trg_validate(uid, 'account.invoice', inv.id, 'invoice_cancel', cr) |
3114 | - self.write(cr,uid,ids,{'state':'cancel'}) |
3115 | - for (id,name) in self.name_get(cr, uid, ids): |
3116 | - message = _("Purchase order '%s' is cancelled.") % name |
3117 | - self.log(cr, uid, id, message) |
3118 | + def button_dummy(self, cr, uid, ids, context=None): |
3119 | return True |
3120 | |
3121 | - def action_picking_create(self,cr, uid, ids, *args): |
3122 | - picking_id = False |
3123 | - for order in self.browse(cr, uid, ids): |
3124 | - loc_id = order.partner_id.property_stock_supplier.id |
3125 | - istate = 'none' |
3126 | - if order.invoice_method=='picking': |
3127 | - istate = '2binvoiced' |
3128 | - pick_name = self.pool.get('ir.sequence').get(cr, uid, 'stock.picking.in') |
3129 | - picking_id = self.pool.get('stock.picking').create(cr, uid, { |
3130 | - 'name': pick_name, |
3131 | - 'origin': order.name+((order.origin and (':'+order.origin)) or ''), |
3132 | - 'type': 'in', |
3133 | - 'address_id': order.dest_address_id.id or order.partner_address_id.id, |
3134 | - 'invoice_state': istate, |
3135 | - 'purchase_id': order.id, |
3136 | - 'company_id': order.company_id.id, |
3137 | - 'move_lines' : [], |
3138 | - }) |
3139 | - todo_moves = [] |
3140 | - for order_line in order.order_line: |
3141 | - if not order_line.product_id: |
3142 | - continue |
3143 | - if order_line.product_id.product_tmpl_id.type in ('product', 'consu'): |
3144 | - dest = order.location_id.id |
3145 | - move = self.pool.get('stock.move').create(cr, uid, { |
3146 | - 'name': order.name + ': ' +(order_line.name or ''), |
3147 | - 'product_id': order_line.product_id.id, |
3148 | - 'product_qty': order_line.product_qty, |
3149 | - 'product_uos_qty': order_line.product_qty, |
3150 | - 'product_uom': order_line.product_uom.id, |
3151 | - 'product_uos': order_line.product_uom.id, |
3152 | - 'date': order_line.date_planned, |
3153 | - 'date_expected': order_line.date_planned, |
3154 | - 'location_id': loc_id, |
3155 | - 'location_dest_id': dest, |
3156 | - 'picking_id': picking_id, |
3157 | - 'move_dest_id': order_line.move_dest_id.id, |
3158 | - 'state': 'draft', |
3159 | - 'purchase_line_id': order_line.id, |
3160 | - 'company_id': order.company_id.id, |
3161 | - 'price_unit': order_line.price_unit |
3162 | - }) |
3163 | - if order_line.move_dest_id: |
3164 | - self.pool.get('stock.move').write(cr, uid, [order_line.move_dest_id.id], {'location_id':order.location_id.id}) |
3165 | - todo_moves.append(move) |
3166 | - self.pool.get('stock.move').action_confirm(cr, uid, todo_moves) |
3167 | - self.pool.get('stock.move').force_assign(cr, uid, todo_moves) |
3168 | - wf_service = netsvc.LocalService("workflow") |
3169 | - wf_service.trg_validate(uid, 'stock.picking', picking_id, 'button_confirm', cr) |
3170 | - raise |
3171 | - return picking_id |
3172 | - |
3173 | - def _hook_copy_name(self, cr, uid, ids, context=None, *args, **kwargs): |
3174 | - ''' |
3175 | - HOOK from purchase>purchase.py for COPY function. Modification of default copy values |
3176 | - define which name value will be used |
3177 | - ''' |
3178 | - return {'state':'draft', |
3179 | - 'shipped':False, |
3180 | - 'invoiced':False, |
3181 | - 'invoice_ids': [], |
3182 | - 'picking_ids': [], |
3183 | - 'name': self.pool.get('ir.sequence').get(cr, uid, 'purchase.order'), |
3184 | - } |
3185 | - |
3186 | - def copy(self, cr, uid, id, default=None, context=None): |
3187 | - if not default: |
3188 | - default = {} |
3189 | - update_values = self._hook_copy_name(cr, uid, [id], context=context, default=default) |
3190 | - default.update(update_values) |
3191 | - return super(purchase_order, self).copy(cr, uid, id, default, context) |
3192 | - |
3193 | def _hook_o_line_value(self, cr, uid, *args, **kwargs): |
3194 | - ''' |
3195 | - Hook to change the values of the PO line |
3196 | - ''' |
3197 | - return kwargs['o_line'] |
3198 | + o_line = super(purchase_order, self)._hook_o_line_value(cr, uid, *args, **kwargs) |
3199 | + order_line = kwargs['order_line'] |
3200 | + |
3201 | + # Copy all fields except order_id and analytic_distribution_id |
3202 | + fields = ['product_uom', 'price_unit', 'move_dest_id', 'product_qty', 'partner_id', |
3203 | + 'confirmed_delivery_date', 'nomenclature_description', 'default_code', |
3204 | + 'nomen_manda_0', 'nomen_manda_1', 'nomen_manda_2', 'nomen_manda_3', |
3205 | + 'nomenclature_code', 'name', 'default_name', 'comment', 'date_planned', |
3206 | + 'to_correct_ok', 'text_error', 'select_fo', 'project_ref', 'external_ref', |
3207 | + 'nomen_sub_0', 'nomen_sub_1', 'nomen_sub_2', 'nomen_sub_3', 'nomen_sub_4', |
3208 | + 'nomen_sub_5', 'linked_sol_id', 'change_price_manually', 'old_price_unit', |
3209 | + 'origin', 'account_analytic_id', 'product_id', 'company_id', 'notes', 'taxes_id', |
3210 | + 'link_so_id', 'from_fo', 'sale_order_line_id', 'tender_line_id', 'dest_partner_id'] |
3211 | + |
3212 | + for field in fields: |
3213 | + field_val = getattr(order_line, field) |
3214 | + if isinstance(field_val, browse_record): |
3215 | + field_val = field_val.id |
3216 | + elif isinstance(field_val, browse_null): |
3217 | + field_val = False |
3218 | + elif isinstance(field_val, list): |
3219 | + field_val = ((6, 0, tuple([v.id for v in field_val])),) |
3220 | + o_line[field] = field_val |
3221 | + |
3222 | + |
3223 | + # Set the analytic distribution |
3224 | + distrib_id = False |
3225 | + if order_line.analytic_distribution_id: |
3226 | + distrib_id = self.pool.get('analytic.distribution').copy(cr, uid, order_line.analytic_distribution_id.id) |
3227 | + elif order_line.order_id.analytic_distribution_id: |
3228 | + distrib_id = self.pool.get('analytic.distribution').copy(cr, uid, order_line.order_id.analytic_distribution_id.id) |
3229 | + |
3230 | + o_line['analytic_distribution_id'] = distrib_id |
3231 | + |
3232 | + return o_line |
3233 | + |
3234 | |
3235 | def _hook_order_infos(self, cr, uid, *args, **kwargs): |
3236 | ''' |
3237 | Hook to change the values of the PO |
3238 | ''' |
3239 | - return kwargs['order_infos'] |
3240 | + order_infos = super(purchase_order, self)._hook_order_infos(cr, uid, *args, **kwargs) |
3241 | + order_id = kwargs['order_id'] |
3242 | + |
3243 | + fields = ['invoice_method', 'minimum_planned_date', 'order_type', |
3244 | + 'categ', 'priority', 'internal_type', 'arrival_date', |
3245 | + 'transport_type', 'shipment_date', 'ready_to_ship_date', |
3246 | + 'cross_docking_ok', 'delivery_confirmed_date', |
3247 | + 'est_transport_lead_time', 'transport_mode', 'location_id', |
3248 | + 'dest_address_id', 'incoterm_id'] |
3249 | + |
3250 | + |
3251 | + delivery_requested_date = getattr(order_id, 'delivery_requested_date') |
3252 | + if not order_infos.get('delivery_requested_date') or delivery_requested_date < order_infos['delivery_requested_date']: |
3253 | + order_infos['delivery_requested_date'] = delivery_requested_date |
3254 | + |
3255 | + |
3256 | + for field in fields: |
3257 | + field_val = getattr(order_id, field) |
3258 | + if isinstance(field_val, browse_record): |
3259 | + field_val = field_val.id |
3260 | + elif isinstance(field_val, browse_null): |
3261 | + field_val = False |
3262 | + elif isinstance(field_val, list): |
3263 | + field_val = ((6, 0, tuple([v.id for v in field_val])),) |
3264 | + order_infos[field] = field_val |
3265 | + |
3266 | + return order_infos |
3267 | |
3268 | def do_merge(self, cr, uid, ids, context=None): |
3269 | """ |
3270 | @@ -633,11 +1047,11 @@ |
3271 | o_line[field] = field_val |
3272 | o_line['uom_factor'] = order_line.product_uom and order_line.product_uom.factor or 1.0 |
3273 | o_line = self._hook_o_line_value(cr, uid, o_line=o_line, order_line=order_line) |
3274 | - if order_line.procurement_id: |
3275 | + if order_line.linked_sol_id: |
3276 | no_proc_ids.append(order_line.id) |
3277 | |
3278 | if no_proc_ids: |
3279 | - line_obj.write(cr, uid, no_proc_ids, {'procurement_id': False}, context=context) |
3280 | + line_obj.write(cr, uid, no_proc_ids, {'linked_sol_id': False}, context=context) |
3281 | |
3282 | allorders = [] |
3283 | orders_info = {} |
3284 | @@ -664,336 +1078,916 @@ |
3285 | wf_service.trg_validate(uid, 'purchase.order', old_id, 'purchase_cancel', cr) |
3286 | return orders_info |
3287 | |
3288 | + def purchase_cancel(self, cr, uid, ids, context=None): |
3289 | + ''' |
3290 | + Call the wizard to ask if you want to re-source the line |
3291 | + ''' |
3292 | + line_obj = self.pool.get('purchase.order.line') |
3293 | + wiz_obj = self.pool.get('purchase.order.cancel.wizard') |
3294 | + exp_sol_obj = self.pool.get('expected.sale.order.line') |
3295 | + so_obj = self.pool.get('sale.order') |
3296 | + data_obj = self.pool.get('ir.model.data') |
3297 | + wf_service = netsvc.LocalService("workflow") |
3298 | + |
3299 | + if context is None: |
3300 | + context = {} |
3301 | + |
3302 | + if isinstance(ids, (int, long)): |
3303 | + ids = [ids] |
3304 | + |
3305 | + if context.get('rfq_ok', False): |
3306 | + view_id = data_obj.get_object_reference(cr, uid, 'tender_flow', 'rfq_cancel_wizard_form_view')[1] |
3307 | + else: |
3308 | + view_id = data_obj.get_object_reference(cr, uid, 'purchase_override', 'purchase_order_cancel_wizard_form_view')[1] |
3309 | + |
3310 | + for po in self.browse(cr, uid, ids, context=context): |
3311 | + for pol in po.order_line: |
3312 | + wiz_id = wiz_obj.create(cr, uid, {'order_id': po.id}, context=context) |
3313 | + return { |
3314 | + 'type': 'ir.actions.act_window', |
3315 | + 'res_model': 'purchase.order.cancel.wizard', |
3316 | + 'res_id': wiz_id, |
3317 | + 'view_type': 'form', |
3318 | + 'view_mode': 'form', |
3319 | + 'view_id': [view_id], |
3320 | + 'target': 'new', |
3321 | + 'context': context |
3322 | + } |
3323 | + |
3324 | + return True |
3325 | + |
3326 | + def _check_restriction_line(self, cr, uid, ids, context=None): |
3327 | + ''' |
3328 | + Check restriction on products |
3329 | + ''' |
3330 | + if isinstance(ids, (int, long)): |
3331 | + ids = [ids] |
3332 | + |
3333 | + line_obj = self.pool.get('purchase.order.line') |
3334 | + res = True |
3335 | + |
3336 | + for order in self.read(cr, uid, ids, ['order_line'], context=context): |
3337 | + res = res and line_obj._check_restriction_line(cr, uid, order['order_line'], context=context) |
3338 | + |
3339 | + return res |
3340 | + |
3341 | + def _check_user_company(self, cr, uid, company_id, context=None): |
3342 | + ''' |
3343 | + Remove the possibility to make a PO to user's company |
3344 | + ''' |
3345 | + user_company_id = self.pool.get('res.users').read(cr, uid, uid, ['company_id'], context=context)['company_id'][0] |
3346 | + if company_id == user_company_id: |
3347 | + raise osv.except_osv(_('Error'), _('You cannot made a purchase order to your own company !')) |
3348 | + |
3349 | + return True |
3350 | + |
3351 | + |
3352 | + def onchange_internal_type(self, cr, uid, ids, order_type, partner_id, categ, dest_partner_id=False, warehouse_id=False, delivery_requested_date=False): |
3353 | + ''' |
3354 | + Changes the invoice method of the purchase order according to |
3355 | + the choosen order type |
3356 | + Changes the partner to local market if the type is Purchase List |
3357 | + ''' |
3358 | + partner_obj = self.pool.get('res.partner') |
3359 | + v = {} |
3360 | + # the domain on the onchange was replace by a several fields.function that you can retrieve in the |
3361 | + # file msf_custom_settings/view/purchase_view.xml: domain="[('supplier', '=', True), ('id', '!=', company_id), ('check_partner_po', '=', order_type), ('check_partner_rfq', '=', tender_id)]" |
3362 | + w = {} |
3363 | + local_market = None |
3364 | + partner = partner_id and partner_obj.read(cr, uid, partner_id, ['partner_type']) or False |
3365 | + |
3366 | + if ids: |
3367 | + order_types_dict = dict((x, y) for x, y in ORDER_TYPES_SELECTION) |
3368 | + err = [] |
3369 | + for order in self.read(cr, uid, ids, ['name', 'fixed_order_type', 'order_type', 'is_a_counterpart']): |
3370 | + if order['is_a_counterpart'] and order_type != 'loan': |
3371 | + err.append(_('%s: This purchase order is a loan counterpart. You cannot change its order type') % order['name']) |
3372 | + else: |
3373 | + json_info = json.loads(order['fixed_order_type']) |
3374 | + if json_info and order_type not in json_info: |
3375 | + allowed_type = ' / '.join(order_types_dict.get(x) for x in json_info) |
3376 | + err.append( |
3377 | + _('%s: Only %s order types are allowed for this purchase order') % (order['name'], allowed_type)) |
3378 | + |
3379 | + if err: |
3380 | + return { |
3381 | + 'warning': { |
3382 | + 'title': _('Error'), |
3383 | + 'message': '\n'.join(x for x in err), |
3384 | + }, |
3385 | + 'value': { |
3386 | + 'order_type': order['order_type'], |
3387 | + } |
3388 | + } |
3389 | + |
3390 | + # check if the current PO was created from scratch : |
3391 | + if order_type == 'direct': |
3392 | + if not self.pool.get('purchase.order.line').search_exist(cr, uid, [('order_id', 'in', ids), ('linked_sol_id', '=', False)]): |
3393 | + order_type_value = self.read(cr, uid, ids, ['order_type']) |
3394 | + order_type_value = order_type_value[0].get('order_type', 'regular') if order_type_value else 'regular' |
3395 | + return { |
3396 | + 'value': {'order_type': order_type_value}, |
3397 | + 'warning': { |
3398 | + 'title': _('Error'), |
3399 | + 'message': _('You cannot create a direct purchase order from scratch') |
3400 | + }, |
3401 | + } |
3402 | + |
3403 | + # Search the local market partner id |
3404 | + data_obj = self.pool.get('ir.model.data') |
3405 | + data_id = data_obj.search(cr, uid, |
3406 | + [('module', '=', 'order_types'), |
3407 | + ('model', '=', 'res.partner'), |
3408 | + ('name', '=', 'res_partner_local_market')], |
3409 | + limit=1, order='NO_ORDER') |
3410 | + if data_id: |
3411 | + local_market = data_obj.read(cr, uid, data_id, ['res_id'])[0]['res_id'] |
3412 | + |
3413 | + if order_type == 'loan': |
3414 | + setup = self.pool.get('unifield.setup.configuration').get_config(cr, uid) |
3415 | + |
3416 | + if not setup.field_orders_ok: |
3417 | + return {'value': {'order_type': 'regular'}, |
3418 | + 'warning': {'title': 'Error', |
3419 | + 'message': 'The Field orders feature is not activated on your system, so, you cannot create a Loan Purchase Order !'}} |
3420 | + |
3421 | + if order_type in ['donation_exp', 'donation_st']: |
3422 | + v['invoice_method'] = partner and partner['partner_type'] == 'section' and 'picking' or 'manual' |
3423 | + elif order_type == 'loan': |
3424 | + v['invoice_method'] = 'manual' |
3425 | + elif order_type in ['direct']: |
3426 | + v['invoice_method'] = 'order' |
3427 | + elif order_type in ['in_kind', 'purchase_list']: |
3428 | + v['invoice_method'] = 'picking' |
3429 | + else: |
3430 | + v['invoice_method'] = 'picking' |
3431 | + |
3432 | + company_id = self.pool.get('res.users').browse(cr, uid, uid).company_id.partner_id.id |
3433 | + |
3434 | + if order_type == 'direct' and dest_partner_id and dest_partner_id != company_id: |
3435 | + cp_address_id = self.pool.get('res.partner').address_get(cr, uid, dest_partner_id, ['delivery'])['delivery'] |
3436 | + v.update({'dest_address_id': cp_address_id}) |
3437 | + elif order_type == 'direct': |
3438 | + v.update({'dest_address_id': False, 'dest_partner_id': False}) |
3439 | + else: |
3440 | + cp_address_id = self.pool.get('res.partner').address_get(cr, uid, company_id, ['delivery'])['delivery'] |
3441 | + v.update({'dest_address_id': cp_address_id, 'dest_partner_id': company_id}) |
3442 | + |
3443 | + if partner and partner_id != local_market: |
3444 | + if partner['partner_type'] in ('internal', 'esc') and order_type in ('regular', 'direct'): |
3445 | + v['invoice_method'] = 'manual' |
3446 | + elif partner['partner_type'] not in ('external', 'esc') and order_type == 'direct': |
3447 | + v.update({'partner_address_id': False, 'partner_id': False, 'pricelist_id': False,}) |
3448 | + w.update({'message': 'You cannot have a Direct Purchase Order with a partner which is not external or an ESC', |
3449 | + 'title': 'An error has occurred !'}) |
3450 | + elif partner_id and partner_id == local_market and order_type != 'purchase_list': |
3451 | + v['partner_id'] = None |
3452 | + v['partner_address_id'] = None |
3453 | + v['pricelist_id'] = None |
3454 | + |
3455 | + if order_type == 'purchase_list': |
3456 | + if local_market: |
3457 | + partner = self.pool.get('res.partner').browse(cr, uid, local_market) |
3458 | + v['partner_id'] = partner.id |
3459 | + if partner.address: |
3460 | + v['partner_address_id'] = partner.address[0].id |
3461 | + if partner.property_product_pricelist_purchase: |
3462 | + v['pricelist_id'] = partner.property_product_pricelist_purchase.id |
3463 | + elif order_type == 'direct': |
3464 | + v['cross_docking_ok'] = False |
3465 | + |
3466 | + return {'value': v, 'warning': w} |
3467 | + |
3468 | + def onchange_partner_id(self, cr, uid, ids, part, *a, **b): |
3469 | + ''' |
3470 | + Fills the Requested and Confirmed delivery dates |
3471 | + ''' |
3472 | + if isinstance(ids, (int, long)): |
3473 | + ids = [ids] |
3474 | + |
3475 | + if not part: |
3476 | + return {'value':{'partner_address_id': False, 'fiscal_position': False}} |
3477 | + |
3478 | + addr = self.pool.get('res.partner').address_get(cr, uid, [part], ['default']) |
3479 | + part = self.pool.get('res.partner').browse(cr, uid, part) |
3480 | + pricelist = part.property_product_pricelist_purchase.id |
3481 | + fiscal_position = part.property_account_position and part.property_account_position.id or False |
3482 | + res = {'value':{'partner_address_id': addr['default'], 'pricelist_id': pricelist, 'fiscal_position': fiscal_position}} |
3483 | + |
3484 | + |
3485 | + partner_obj = self.pool.get('res.partner') |
3486 | + product_obj = self.pool.get('product.product') |
3487 | + partner = partner_obj.read(cr, uid, part.id, ['partner_type']) |
3488 | + if ids: |
3489 | + # Check the restrction of product in lines |
3490 | + for order in self.browse(cr, uid, ids): |
3491 | + for line in order.order_line: |
3492 | + if line.product_id: |
3493 | + res, test = product_obj._on_change_restriction_error(cr, uid, line.product_id.id, field_name='partner_id', values=res, vals={'partner_id': part}) |
3494 | + if test: |
3495 | + res.setdefault('value', {}).update({'partner_address_id': False}) |
3496 | + return res |
3497 | + if partner['partner_type'] in ('internal', 'esc'): |
3498 | + res['value']['invoice_method'] = 'manual' |
3499 | + elif ids and partner['partner_type'] == 'intermission': |
3500 | + try: |
3501 | + intermission = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'analytic_distribution', |
3502 | + 'analytic_account_project_intermission')[1] |
3503 | + except ValueError: |
3504 | + intermission = 0 |
3505 | + cr.execute('''select po.id from purchase_order po |
3506 | + left join purchase_order_line pol on pol.order_id = po.id |
3507 | + left join cost_center_distribution_line cl1 on cl1.distribution_id = po.analytic_distribution_id |
3508 | + left join cost_center_distribution_line cl2 on cl2.distribution_id = pol.analytic_distribution_id |
3509 | + where po.id in %s and (cl1.analytic_id!=%s or cl2.analytic_id!=%s)''', (tuple(ids), intermission, intermission)) |
3510 | + if cr.rowcount > 0: |
3511 | + res.setdefault('warning', {}) |
3512 | + msg = _('You set an intermission partner, at validation Cost Centers will be changed to intermission.') |
3513 | + if res.get('warning', {}).get('message'): |
3514 | + res['warning']['message'] += msg |
3515 | + else: |
3516 | + res['warning'] = {'title': _('Warning'), 'message': msg} |
3517 | + return res |
3518 | + |
3519 | + def onchange_warehouse_id(self, cr, uid, ids, warehouse_id, order_type, dest_address_id): |
3520 | + ''' |
3521 | + Change the destination address to the destination address of the company if False |
3522 | + ''' |
3523 | + res = {} |
3524 | + if not warehouse_id: |
3525 | + wh_info = self.pool.get('stock.warehouse').read(cr, uid, [warehouse_id], ['lot_input_id']) |
3526 | + res = {'value':{'location_id': wh_info[0]['lot_input_id'][0], 'dest_address_id': False, 'cross_docking_ok': False}} |
3527 | + |
3528 | + if not res.get('value', {}).get('dest_address_id') and order_type!='direct': |
3529 | + cp_address_id = self.pool.get('res.partner').address_get(cr, uid, self.pool.get('res.users').browse(cr, uid, uid).company_id.partner_id.id, ['delivery'])['delivery'] |
3530 | + if 'value' in res: |
3531 | + res['value'].update({'dest_address_id': cp_address_id}) |
3532 | + else: |
3533 | + res.update({'value': {'dest_address_id': cp_address_id}}) |
3534 | + if order_type == 'direct' or dest_address_id: |
3535 | + if 'dest_address_id' in res.get('value', {}): |
3536 | + res['value'].pop('dest_address_id') |
3537 | + |
3538 | + return res |
3539 | + |
3540 | + def on_change_dest_partner_id(self, cr, uid, ids, dest_partner_id, context=None): |
3541 | + ''' |
3542 | + Fill automatically the destination address according to the destination partner |
3543 | + ''' |
3544 | + v = {} |
3545 | + |
3546 | + if not context: |
3547 | + context = {} |
3548 | + |
3549 | + if not dest_partner_id: |
3550 | + v.update({'dest_address_id': False}) |
3551 | + else: |
3552 | + delivery_addr = self.pool.get('res.partner').address_get(cr, uid, dest_partner_id, ['delivery']) |
3553 | + v.update({'dest_address_id': delivery_addr['delivery']}) |
3554 | + return {'value': v} |
3555 | + |
3556 | + def change_currency(self, cr, uid, ids, context=None): |
3557 | + ''' |
3558 | + Launches the wizard to change the currency and update lines |
3559 | + ''' |
3560 | + if not context: |
3561 | + context = {} |
3562 | + |
3563 | + if isinstance(ids, (int, long)): |
3564 | + ids = [ids] |
3565 | + |
3566 | + for order in self.browse(cr, uid, ids, context=context): |
3567 | + data = {'order_id': order.id, |
3568 | + 'partner_id': order.partner_id.id, |
3569 | + 'partner_type': order.partner_id.partner_type, |
3570 | + 'new_pricelist_id': order.pricelist_id.id, |
3571 | + 'currency_rate': 1.00, |
3572 | + 'old_pricelist_id': order.pricelist_id.id} |
3573 | + wiz = self.pool.get('purchase.order.change.currency').create(cr, uid, data, context=context) |
3574 | + return {'type': 'ir.actions.act_window', |
3575 | + 'res_model': 'purchase.order.change.currency', |
3576 | + 'view_type': 'form', |
3577 | + 'view_mode': 'form', |
3578 | + 'res_id': wiz, |
3579 | + 'target': 'new'} |
3580 | + |
3581 | + return True |
3582 | + |
3583 | + def order_line_change(self, cr, uid, ids, order_line): |
3584 | + res = {'no_line': True} |
3585 | + |
3586 | + if order_line: |
3587 | + res = {'no_line': False} |
3588 | + |
3589 | + return {'value': res} |
3590 | + |
3591 | + def _get_destination_ok(self, cr, uid, lines, context): |
3592 | + dest_ok = False |
3593 | + for line in lines: |
3594 | + is_inkind = line.order_id and line.order_id.order_type == 'in_kind' or False |
3595 | + dest_ok = line.account_4_distribution and line.account_4_distribution.destination_ids or False |
3596 | + if not dest_ok: |
3597 | + if is_inkind: |
3598 | + raise osv.except_osv(_('Error'), _('No destination found. An In-kind Donation account is probably missing for this line: %s.') % (line.name or '')) |
3599 | + raise osv.except_osv(_('Error'), _('No destination found for this line: %s.') % (line.name or '',)) |
3600 | + return dest_ok |
3601 | + |
3602 | + def check_analytic_distribution(self, cr, uid, ids, context=None, create_missing=False): |
3603 | + """ |
3604 | + Check analytic distribution validity for given PO. |
3605 | + Also check that partner have a donation account (is PO is in_kind) |
3606 | + """ |
3607 | + # Objects |
3608 | + pol_obj = self.pool.get('purchase.order.line') |
3609 | + |
3610 | + if context is None: |
3611 | + context = {} |
3612 | + |
3613 | + if isinstance(ids, (int, long)): |
3614 | + ids = [ids] |
3615 | + |
3616 | + po_line_ids = pol_obj.search(cr, uid, [('oder_id', 'in', id), ('state', '!=', 'cancelled')], context=context) |
3617 | + if po_line_ids: |
3618 | + return pol_obj.check_analytic_distribution(cr, uid, po_line_ids, context=context, create_missing=create_missing) |
3619 | + return True |
3620 | + |
3621 | + def check_if_stock_take_date_with_esc_partner(self, cr, uid, ids, context=None): |
3622 | + """ |
3623 | + Check if the PO and all lines have a date of stock take with an ESC Partner |
3624 | + """ |
3625 | + if isinstance(ids, (int, long)): |
3626 | + ids = [ids] |
3627 | + |
3628 | + for po in self.browse(cr, uid, ids, context=context): |
3629 | + if po.partner_type == 'esc': |
3630 | + if not po.stock_take_date and self.pool.get('purchase.order.line').search_exist(cr, uid, [('order_id', '=', po.id), ('stock_take_date', '=', False)], context=context): |
3631 | + raise osv.except_osv(_('Warning !'), _( |
3632 | + 'The Date of Stock Take is required for a Purchase Order if the Partner is an ESC.')) |
3633 | + if self.pool.get('purchase.order.line').search_exist(cr, uid, [('order_id', '=', po.id), ('stock_take_date', '=', False)], context=context): |
3634 | + raise osv.except_osv(_('Warning !'), _('The Date of Stock Take is required for all Purchase Order lines if the Partner is an ESC.')) |
3635 | + return True |
3636 | + |
3637 | + def get_so_ids_from_po_ids(self, cr, uid, ids, context=None): |
3638 | + ''' |
3639 | + receive the list of purchase order ids |
3640 | + return the list of sale order ids corresponding |
3641 | + ''' |
3642 | + if not context: |
3643 | + context = {} |
3644 | + if isinstance(ids, (int, long)): |
3645 | + ids = [ids] |
3646 | + |
3647 | + so_ids = set() |
3648 | + for po in self.browse(cr, uid, ids, context=context): |
3649 | + for pol in po.order_line: |
3650 | + if pol.linked_sol_id: |
3651 | + so_ids.add(pol.linked_sol_id.order_id.id) |
3652 | + |
3653 | + return list(so_ids) |
3654 | + |
3655 | + def get_sol_ids_from_po_ids(self, cr, uid, ids, context=None): |
3656 | + ''' |
3657 | + receive the list of purchase order ids |
3658 | + return the list of sale order line ids corresponding |
3659 | + ''' |
3660 | + if not context: |
3661 | + context = {} |
3662 | + if isinstance(ids, (int, long)): |
3663 | + ids = [ids] |
3664 | + |
3665 | + sol_ids = set() |
3666 | + for po in self.browse(cr, uid, ids, context=context): |
3667 | + for pol in po.order_line: |
3668 | + if pol.linked_sol_id: |
3669 | + sol_ids.add(pol.linked_sol_id.id) |
3670 | + |
3671 | + return list(sol_ids) |
3672 | + |
3673 | + def compute_confirmed_delivery_date(self, cr, uid, ids, confirmed, prep_lt, ship_lt, est_transport_lead_time, db_date_format, context=None): |
3674 | + ''' |
3675 | + compute the confirmed date |
3676 | + |
3677 | + confirmed must be string |
3678 | + return string corresponding to database format |
3679 | + ''' |
3680 | + assert type(confirmed) == str |
3681 | + confirmed = datetime.strptime(confirmed, db_date_format) |
3682 | + confirmed = confirmed + relativedelta(days=prep_lt or 0) |
3683 | + confirmed = confirmed + relativedelta(days=ship_lt or 0) |
3684 | + confirmed = confirmed + relativedelta(days=est_transport_lead_time or 0) |
3685 | + confirmed = confirmed.strftime(db_date_format) |
3686 | + |
3687 | + return confirmed |
3688 | + |
3689 | + def has_stockable_product(self,cr, uid, ids, *args): |
3690 | + ''' |
3691 | + Override the has_stockable_product to return False |
3692 | + when the order_type of the order is 'direct' |
3693 | + ''' |
3694 | + |
3695 | + # TODO: See with Synchro team which object the system will should create |
3696 | + # to have an Incoming Movement in the destination instance |
3697 | + for order in self.read(cr, uid, ids, ['order_type']): |
3698 | + if order['order_type'] != 'direct': |
3699 | + for order in self.browse(cr, uid, ids): |
3700 | + for order_line in order.order_line: |
3701 | + if order_line.product_id and order_line.product_id.product_tmpl_id.type in ('product', 'consu'): |
3702 | + return True |
3703 | + return False |
3704 | + |
3705 | + def ensure_object(self, cr, uid, model, value): |
3706 | + if isinstance(value, (int, long)): |
3707 | + value = self.pool.get(model).browse(cr, uid, value) |
3708 | + return value |
3709 | + |
3710 | + def get_reason_type_id(self, cr, uid, order, context=None): |
3711 | + |
3712 | + def get_reference(reason): |
3713 | + return self.pool.get('ir.model.data').get_object_reference(cr, uid, 'reason_types_moves', reason)[1] |
3714 | + |
3715 | + order = self.ensure_object(cr, uid, 'purchase.order', order) |
3716 | + |
3717 | + reason_type_id = False |
3718 | + if order.order_type in ('regular', 'purchase_list', 'direct') and \ |
3719 | + order.partner_id.partner_type in ('internal', 'intermission', 'section', 'esc'): |
3720 | + reason_type_id = get_reference('reason_type_internal_supply') |
3721 | + elif order.order_type in ('regular', 'purchase_list', 'direct'): |
3722 | + reason_type_id = get_reference('reason_type_external_supply') |
3723 | + elif order.order_type == 'loan': |
3724 | + reason_type_id = get_reference('reason_type_loan') |
3725 | + elif order.order_type == 'donation_st': |
3726 | + reason_type_id = get_reference('reason_type_donation') |
3727 | + elif order.order_type == 'donation_exp': |
3728 | + reason_type_id = get_reference('reason_type_donation_expiry') |
3729 | + elif order.order_type == 'in_kind': |
3730 | + reason_type_id = get_reference('reason_type_in_kind_donation') |
3731 | + return reason_type_id |
3732 | + |
3733 | + def create_picking(self, cr, uid, order, context=None): |
3734 | + if context is None: |
3735 | + context = {} |
3736 | + |
3737 | + order = self.ensure_object(cr, uid, 'purchase.order', order) |
3738 | + |
3739 | + values = { |
3740 | + 'name': self.pool.get('ir.sequence').get(cr, uid, 'stock.picking.in'), |
3741 | + 'origin': order.name + ((order.origin and (':' + order.origin)) or ''), |
3742 | + 'type': 'in', |
3743 | + 'partner_id2': order.partner_id.id, |
3744 | + 'address_id': order.partner_address_id.id or False, |
3745 | + 'invoice_state': '2binvoiced' if order.invoice_method == 'picking' else 'none', |
3746 | + 'purchase_id': order.id, |
3747 | + 'company_id': order.company_id.id, |
3748 | + 'move_lines': [], |
3749 | + } |
3750 | + |
3751 | + reason_type_id = self.get_reason_type_id(cr, uid, order, context) |
3752 | + if reason_type_id: |
3753 | + values.update({'reason_type_id': reason_type_id}) |
3754 | + |
3755 | + return self.pool.get('stock.picking').create(cr, uid, values, context=context) |
3756 | + |
3757 | + def create_picking_line(self, cr, uid, picking_id, order_line, context=None): |
3758 | + if context is None: |
3759 | + context = {} |
3760 | + |
3761 | + order_line = self.ensure_object(cr, uid, 'purchase.order.line', order_line) |
3762 | + if not order_line: |
3763 | + return False |
3764 | + |
3765 | + picking_id = self.ensure_object(cr, uid, 'stock.picking', picking_id) |
3766 | + order = order_line.order_id |
3767 | + dest = order.location_id.id |
3768 | + |
3769 | + move_obj = self.pool.get('stock.move') |
3770 | + data_obj = self.pool.get('ir.model.data') |
3771 | + |
3772 | + # service with reception are directed to Service Location |
3773 | + if order_line.product_id.type == 'service_recep' and not order.cross_docking_ok: |
3774 | + dest = self.pool.get('stock.location').get_service_location(cr, uid) |
3775 | + else: |
3776 | + sol = order_line.linked_sol_id |
3777 | + if sol: |
3778 | + if not (sol.order_id and sol.order_id.procurement_request): |
3779 | + pass |
3780 | + elif order_line.product_id.type == 'service_recep': |
3781 | + dest = self.pool.get('stock.location').get_service_location(cr, uid) |
3782 | + elif order_line.product_id.type == 'consu': |
3783 | + dest = data_obj.get_object_reference(cr, uid, 'stock_override', 'stock_location_non_stockable')[1] |
3784 | + elif sol.order_id.location_requestor_id.usage != 'customer': |
3785 | + dest = data_obj.get_object_reference(cr, uid, 'msf_cross_docking', 'stock_location_input')[1] |
3786 | + |
3787 | + values = { |
3788 | + 'name': ''.join((order.name, ': ', (order_line.name or ''))), |
3789 | + 'product_id': order_line.product_id.id, |
3790 | + 'product_qty': order_line.product_qty, |
3791 | + 'product_uos_qty': order_line.product_qty, |
3792 | + 'product_uom': order_line.product_uom.id, |
3793 | + 'product_uos': order_line.product_uom.id, |
3794 | + 'location_id': order.partner_id.property_stock_supplier.id, |
3795 | + 'location_dest_id': dest, |
3796 | + 'picking_id': picking_id.id, |
3797 | + 'move_dest_id': order_line.move_dest_id.id, |
3798 | + 'state': 'draft', |
3799 | + 'purchase_line_id': order_line.id, |
3800 | + 'company_id': order.company_id.id, |
3801 | + 'price_currency_id': order.pricelist_id.currency_id.id, |
3802 | + 'price_unit': order_line.price_unit, |
3803 | + 'date': order_line.confirmed_delivery_date, |
3804 | + 'date_expected': order_line.confirmed_delivery_date or order_line.date_planned, |
3805 | + 'line_number': order_line.line_number, |
3806 | + 'comment': order_line.comment, |
3807 | + } |
3808 | + |
3809 | + if picking_id.reason_type_id: |
3810 | + values.update({'reason_type_id': picking_id.reason_type_id.id}) |
3811 | + |
3812 | + ctx = context.copy() |
3813 | + ctx['bypass_store_function'] = [ |
3814 | + ('stock.picking', ['dpo_incoming', 'dpo_out', 'overall_qty', 'line_state']) |
3815 | + ] |
3816 | + |
3817 | + return move_obj.create(cr, uid, values, context=ctx) |
3818 | + |
3819 | + |
3820 | + def _get_location_id(self, cr, uid, vals, warehouse_id=False, context=None): |
3821 | + """ |
3822 | + Get the location_id according to the cross_docking_ok option |
3823 | + Return vals |
3824 | + """ |
3825 | + if 'cross_docking_ok' not in vals: |
3826 | + return vals |
3827 | + |
3828 | + stock_warehouse_obj = self.pool.get('stock.warehouse') |
3829 | + if not warehouse_id: |
3830 | + warehouse_id = stock_warehouse_obj.search(cr, uid, [], context=context)[0] |
3831 | + |
3832 | + if isinstance(warehouse_id, (str,unicode)): |
3833 | + try: |
3834 | + warehouse_id = int(warehouse_id) |
3835 | + except ValueError: |
3836 | + raise osv.except_osv( |
3837 | + _('Error'), |
3838 | + _('The field \'warehouse_id\' is a float field but value is a string - Please contact your administrator'), |
3839 | + ) |
3840 | + |
3841 | + if not vals.get('cross_docking_ok', False): |
3842 | + vals.update({'location_id': stock_warehouse_obj.read(cr, uid, warehouse_id, ['lot_input_id'], context=context)['lot_input_id'][0]}) |
3843 | + elif vals.get('cross_docking_ok', False): |
3844 | + vals.update({'location_id': self.pool.get('stock.location').get_cross_docking_location(cr, uid)}) |
3845 | + |
3846 | + return vals |
3847 | + |
3848 | + def set_manually_done(self, cr, uid, ids, all_doc=True, context=None): |
3849 | + ''' |
3850 | + Set the PO to done state |
3851 | + ''' |
3852 | + wf_service = netsvc.LocalService("workflow") |
3853 | + so_obj = self.pool.get('sale.order') |
3854 | + move_obj = self.pool.get('stock.move') |
3855 | + |
3856 | + if context is None: |
3857 | + context = {} |
3858 | + if isinstance(ids, (int, long)): |
3859 | + ids = [ids] |
3860 | + |
3861 | + order_lines = [] |
3862 | + for order in self.browse(cr, uid, ids, context=context): |
3863 | + for line in order.order_line: |
3864 | + order_lines.append(line.id) |
3865 | + |
3866 | + # Done picking |
3867 | + for pick in order.picking_ids: |
3868 | + if pick.state not in ('cancel', 'done'): |
3869 | + wf_service.trg_validate(uid, 'stock.picking', pick.id, 'manually_done', cr) |
3870 | + |
3871 | + # Done loan counterpart |
3872 | + if order.loan_id and order.loan_id.state not in ('cancel', 'done') and not context.get('loan_id', False) == order.id: |
3873 | + loan_context = context.copy() |
3874 | + loan_context.update({'loan_id': order.id}) |
3875 | + so_obj.set_manually_done(cr, uid, order.loan_id.id, all_doc=all_doc, context=loan_context) |
3876 | + |
3877 | + # Done stock moves |
3878 | + move_ids = move_obj.search(cr, uid, [('purchase_line_id', 'in', order_lines), ('state', 'not in', ('cancel', 'done'))], context=context) |
3879 | + move_obj.set_manually_done(cr, uid, move_ids, all_doc=all_doc, context=context) |
3880 | + |
3881 | + # Cancel all procurement ordes which have generated one of these PO |
3882 | + proc_ids = self.pool.get('procurement.order').search(cr, uid, [('purchase_id', 'in', ids)], context=context) |
3883 | + for proc in self.pool.get('procurement.order').browse(cr, uid, proc_ids, context=context): |
3884 | + if proc.move_id and proc.move_id.id: |
3885 | + move_obj.write(cr, uid, [proc.move_id.id], {'state': 'cancel'}, context=context) |
3886 | + wf_service.trg_validate(uid, 'procurement.order', proc.id, 'subflow.cancel', cr) |
3887 | + |
3888 | + if all_doc: |
3889 | + # Detach the PO from his workflow and set the state to done |
3890 | + for order_id in self.browse(cr, uid, ids, context=context): |
3891 | + if order_id.rfq_ok and order_id.state == 'draft': |
3892 | + wf_service.trg_validate(uid, 'purchase.order', order_id.id, 'purchase_cancel', cr) |
3893 | + elif order_id.tender_id: |
3894 | + raise osv.except_osv(_('Error'), _('You cannot \'Close\' a Request for Quotation attached to a tender. Please make the tender %s to \'Closed\' before !') % order_id.tender_id.name) |
3895 | + else: |
3896 | + wf_service.trg_delete(uid, 'purchase.order', order_id.id, cr) |
3897 | + # Search the method called when the workflow enter in last activity |
3898 | + wkf_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'purchase', 'act_done')[1] |
3899 | + activity = self.pool.get('workflow.activity').browse(cr, uid, wkf_id, context=context) |
3900 | + _eval_expr(cr, [uid, 'purchase.order', order_id.id], False, activity.action) |
3901 | + |
3902 | + return True |
3903 | + |
3904 | + |
3905 | + def check_empty_po(self, cr, uid, ids, context=None): |
3906 | + """ |
3907 | + If the PO is empty, return a wizard to ask user if he wants |
3908 | + cancel the whole PO |
3909 | + """ |
3910 | + order_wiz_obj = self.pool.get('purchase.order.cancel.wizard') |
3911 | + data_obj = self.pool.get('ir.model.data') |
3912 | + |
3913 | + for po in self.browse(cr, uid, ids, context=context): |
3914 | + if all(x.state in ('cancel', 'done') for x in po.order_line): |
3915 | + wiz_id = order_wiz_obj.create(cr, uid, {'order_id': po.id}, context=context) |
3916 | + if po.rfq_ok: |
3917 | + view_id = data_obj.get_object_reference(cr, uid, 'tender_flow', 'ask_rfq_cancel_wizard_form_view')[1] |
3918 | + else: |
3919 | + view_id = data_obj.get_object_reference(cr, uid, 'purchase_override', 'ask_po_cancel_wizard_form_view')[1] |
3920 | + context['view_id'] = False |
3921 | + return {'type': 'ir.actions.act_window', |
3922 | + 'res_model': 'purchase.order.cancel.wizard', |
3923 | + 'view_type': 'form', |
3924 | + 'view_mode': 'form', |
3925 | + 'view_id': [view_id], |
3926 | + 'res_id': wiz_id, |
3927 | + 'target': 'new', |
3928 | + 'context': context} |
3929 | + |
3930 | + return {'type': 'ir.actions.act_window_close'} |
3931 | + |
3932 | + def round_to_soq(self, cr, uid, ids, context=None): |
3933 | + """ |
3934 | + Create a new thread to check for each line of the order if the quantity |
3935 | + is compatible with the SoQ rounding of the supplier catalogue or |
3936 | + product. If not compatible, update the quantity to match with SoQ rounding. |
3937 | + :param cr: Cursor to the database |
3938 | + :param uid: ID of the res.users that calls the method |
3939 | + :param ids: List of ID of sale.order to check and update |
3940 | + :param context: Context of the call |
3941 | + :return: True |
3942 | + """ |
3943 | + th = threading.Thread( |
3944 | + target=self._do_round_to_soq, |
3945 | + args=(cr, uid, ids, context, True), |
3946 | + ) |
3947 | + th.start() |
3948 | + th.join(5.0) |
3949 | + |
3950 | + return True |
3951 | + |
3952 | + def _do_round_to_soq(self, cr, uid, ids, context=None, use_new_cursor=False): |
3953 | + """ |
3954 | + Check for each line of the order if the quantity is compatible |
3955 | + with the SoQ rounding of the supplier catalogue or product. If |
3956 | + not compatible, update the quantity to match with SoQ rounding. |
3957 | + :param cr: Cursor to the database |
3958 | + :param uid: ID of the res.users that calls the method |
3959 | + :param ids: List of ID of sale.order to check and update |
3960 | + :param context: Context of the call |
3961 | + :param use_new_cursor: True if this method is called into a new thread |
3962 | + :return: True |
3963 | + """ |
3964 | + pol_obj = self.pool.get('purchase.order.line') |
3965 | + uom_obj = self.pool.get('product.uom') |
3966 | + sup_obj = self.pool.get('product.supplierinfo') |
3967 | + |
3968 | + if context is None: |
3969 | + context = {} |
3970 | + |
3971 | + if isinstance(ids, (int, long)): |
3972 | + ids = [ids] |
3973 | + |
3974 | + if use_new_cursor: |
3975 | + cr = pooler.get_db(cr.dbname).cursor() |
3976 | + |
3977 | + try: |
3978 | + self.write(cr, uid, ids, { |
3979 | + 'update_in_progress': True, |
3980 | + }, context=context) |
3981 | + if use_new_cursor: |
3982 | + cr.commit() |
3983 | + |
3984 | + pol_ids = pol_obj.search(cr, uid, [ |
3985 | + ('order_id', 'in', ids), |
3986 | + ('product_id', '!=', False), |
3987 | + ], context=context) |
3988 | + |
3989 | + to_update = {} |
3990 | + for pol in pol_obj.browse(cr, uid, pol_ids, context=context): |
3991 | + # Check only products with defined SoQ quantity |
3992 | + sup_ids = sup_obj.search(cr, uid, [ |
3993 | + ('name', '=', pol.order_id.partner_id.id), |
3994 | + ('product_id', '=', pol.product_id.id), |
3995 | + ], context=context) |
3996 | + if not sup_ids and not pol.product_id.soq_quantity: |
3997 | + continue |
3998 | + |
3999 | + # Get SoQ value |
4000 | + soq = pol.product_id.soq_quantity |
4001 | + soq_uom = pol.product_id.uom_id |
4002 | + if sup_ids: |
4003 | + for sup in sup_obj.browse(cr, uid, sup_ids, context=context): |
4004 | + for pcl in sup.pricelist_ids: |
4005 | + if pcl.rounding and pcl.min_quantity <= pol.product_qty: |
4006 | + soq = pcl.rounding |
4007 | + soq_uom = pcl.uom_id |
4008 | + |
4009 | + if not soq: |
4010 | + continue |
4011 | + |
4012 | + # Get line quantity in SoQ UoM |
4013 | + line_qty = pol.product_qty |
4014 | + if pol.product_uom.id != soq_uom.id: |
4015 | + line_qty = uom_obj._compute_qty_obj(cr, uid, pol.product_uom, pol.product_qty, soq_uom, context=context) |
4016 | + |
4017 | + good_quantity = 0 |
4018 | + if line_qty % soq: |
4019 | + good_quantity = (line_qty - (line_qty % soq)) + soq |
4020 | + |
4021 | + if good_quantity and pol.product_uom.id != soq_uom.id: |
4022 | + good_quantity = uom_obj._compute_qty_obj(cr, uid, soq_uom, good_quantity, pol.product_uom, context=context) |
4023 | + |
4024 | + if good_quantity: |
4025 | + to_update.setdefault(good_quantity, []) |
4026 | + to_update[good_quantity].append(pol.id) |
4027 | + |
4028 | + for qty, line_ids in to_update.iteritems(): |
4029 | + pol_obj.write(cr, uid, line_ids, { |
4030 | + 'product_qty': qty, |
4031 | + 'soq_updated': True, |
4032 | + }, context=context) |
4033 | + except Exception as e: |
4034 | + logger = logging.getLogger('purchase.order.round_to_soq') |
4035 | + logger.error(e) |
4036 | + finally: |
4037 | + self.write(cr, uid, ids, { |
4038 | + 'update_in_progress': False, |
4039 | + }, context=context) |
4040 | + |
4041 | + if use_new_cursor: |
4042 | + cr.commit() |
4043 | + cr.close(True) |
4044 | + |
4045 | + return True |
4046 | + |
4047 | +#CTRL |
4048 | + def update_supplier_info(self, cr, uid, ids, context=None, *args, **kwargs): |
4049 | + ''' |
4050 | + update the supplier info of corresponding products |
4051 | + ''' |
4052 | + info_obj = self.pool.get('product.supplierinfo') |
4053 | + pricelist_info_obj = self.pool.get('pricelist.partnerinfo') |
4054 | + for rfq in self.browse(cr, uid, ids, context=context): |
4055 | + for line in rfq.order_line: |
4056 | + # if the price is updated and a product selected |
4057 | + if line.price_unit and line.product_id: |
4058 | + # get the product |
4059 | + product = line.product_id |
4060 | + # find the corresponding suppinfo with sequence -99 |
4061 | + info_99_list = info_obj.search(cr, uid, [('product_id', '=', product.product_tmpl_id.id), |
4062 | + ('sequence', '=', -99)], |
4063 | + order='NO_ORDER', context=context) |
4064 | + |
4065 | + if info_99_list: |
4066 | + # we drop it |
4067 | + info_obj.unlink(cr, uid, info_99_list, context=context) |
4068 | + |
4069 | + # create the new one |
4070 | + values = {'name': rfq.partner_id.id, |
4071 | + 'product_name': False, |
4072 | + 'product_code': False, |
4073 | + 'sequence' : -99, |
4074 | + #'product_uom': line.product_uom.id, |
4075 | + #'min_qty': 0.0, |
4076 | + #'qty': function |
4077 | + 'product_id' : product.product_tmpl_id.id, |
4078 | + 'delay' : int(rfq.partner_id.default_delay), |
4079 | + #'pricelist_ids': created just after |
4080 | + #'company_id': default value |
4081 | + } |
4082 | + |
4083 | + new_info_id = info_obj.create(cr, uid, values, context=context) |
4084 | + # price lists creation - 'pricelist.partnerinfo |
4085 | + values = {'suppinfo_id': new_info_id, |
4086 | + 'min_quantity': 1.00, |
4087 | + 'price': line.price_unit, |
4088 | + 'uom_id': line.product_uom.id, |
4089 | + 'currency_id': line.currency_id.id, |
4090 | + 'valid_till': rfq.valid_till, |
4091 | + 'purchase_order_line_id': line.id, |
4092 | + 'comment': 'RfQ original quantity for price : %s' % line.product_qty, |
4093 | + } |
4094 | + pricelist_info_obj.create(cr, uid, values, context=context) |
4095 | + |
4096 | + return True |
4097 | + |
4098 | + def generate_po_from_rfq(self, cr, uid, ids, context=None): |
4099 | + ''' |
4100 | + generate a po from the selected request for quotation |
4101 | + ''' |
4102 | + # Objects |
4103 | + line_obj = self.pool.get('purchase.order.line') |
4104 | + |
4105 | + # Some verifications |
4106 | + if context is None: |
4107 | + context = {} |
4108 | + if isinstance(ids, (int, long)): |
4109 | + ids = [ids] |
4110 | + |
4111 | + # update price lists |
4112 | + self.update_supplier_info(cr, uid, ids, context=context) |
4113 | + # copy the po with rfq_ok set to False |
4114 | + data = self.read(cr, uid, ids[0], ['name', 'amount_total'], context=context) |
4115 | + if not data.get('amount_total', 0.00): |
4116 | + raise osv.except_osv( |
4117 | + _('Error'), |
4118 | + _('Generation of PO aborted because no price defined on lines.'), |
4119 | + ) |
4120 | + new_po_id = self.copy(cr, uid, ids[0], {'name': False, 'rfq_ok': False, 'origin': data['name']}, context=dict(context,keepOrigin=True)) |
4121 | + # Remove lines with 0.00 as unit price |
4122 | + no_price_line_ids = line_obj.search(cr, uid, [ |
4123 | + ('order_id', '=', new_po_id), |
4124 | + ('price_unit', '=', 0.00), |
4125 | + ], order='NO_ORDER', context=context) |
4126 | + line_obj.unlink(cr, uid, no_price_line_ids, context=context) |
4127 | + |
4128 | + data = self.read(cr, uid, new_po_id, ['name'], context=context) |
4129 | + # log message describing the previous action |
4130 | + self.log(cr, uid, new_po_id, _('The Purchase Order %s has been generated from Request for Quotation.')%data['name']) |
4131 | + # close the current po |
4132 | + wf_service = netsvc.LocalService("workflow") |
4133 | + wf_service.trg_validate(uid, 'purchase.order', ids[0], 'rfq_done', cr) |
4134 | + |
4135 | + return new_po_id |
4136 | + |
4137 | + |
4138 | + def create_commitment_voucher_from_po(self, cr, uid, ids, context=None): |
4139 | + ''' |
4140 | + Create a new commitment voucher from the given PO |
4141 | + @param ids id of the Purchase order |
4142 | + ''' |
4143 | + if context is None: |
4144 | + context = {} |
4145 | + if isinstance(ids, (int,long)): |
4146 | + ids = [ids] |
4147 | + |
4148 | + commit_id = False |
4149 | + for po in self.pool.get('purchase.order').browse(cr, uid, ids, context=context): |
4150 | + engagement_ids = self.pool.get('account.analytic.journal').search(cr, uid, [ |
4151 | + ('type', '=', 'engagement'), |
4152 | + ('instance_id', '=', self.pool.get('res.users').browse(cr, uid, uid, context).company_id.instance_id.id) |
4153 | + ], limit=1, context=context) |
4154 | + |
4155 | + vals = { |
4156 | + 'journal_id': engagement_ids and engagement_ids[0] or False, |
4157 | + 'currency_id': po.currency_id and po.currency_id.id or False, |
4158 | + 'partner_id': po.partner_id and po.partner_id.id or False, |
4159 | + 'purchase_id': po.id or False, |
4160 | + 'type': 'external' if po.partner_id.partner_type == 'external' else 'manual', |
4161 | + } |
4162 | + # prepare some values |
4163 | + today = time.strftime('%Y-%m-%d') |
4164 | + period_ids = get_period_from_date(self, cr, uid, po.delivery_confirmed_date or today, context=context) |
4165 | + period_id = period_ids and period_ids[0] or False |
4166 | + if not period_id: |
4167 | + raise osv.except_osv(_('Error'), _('No period found for given date: %s.') % (po.delivery_confirmed_date or today)) |
4168 | + date = get_date_in_period(self, cr, uid, po.delivery_confirmed_date or today, period_id, context=context) |
4169 | + vals.update({ |
4170 | + 'date': date, |
4171 | + 'period_id': period_id, |
4172 | + }) |
4173 | + commit_id = self.pool.get('account.commitment').create(cr, uid, vals, context=context) |
4174 | + |
4175 | + # Display a message to inform that a commitment was created |
4176 | + commit_data = self.pool.get('account.commitment').read(cr, uid, commit_id, ['name'], context=context) |
4177 | + message = _("Commitment Voucher %s has been created.") % commit_data.get('name', '') |
4178 | + view_ids = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'analytic_distribution', 'account_commitment_form') |
4179 | + self.pool.get('account.commitment').log(cr, uid, commit_id, message, context={'view_id': view_ids and view_ids[1] or False}) |
4180 | + self.infolog(cr, uid, message) |
4181 | + |
4182 | + # Add analytic distribution from purchase |
4183 | + if po.analytic_distribution_id: |
4184 | + new_distrib_id = self.pool.get('analytic.distribution').copy(cr, uid, po.analytic_distribution_id.id, {}, context=context) |
4185 | + # Update this distribution not to have a link with purchase but with new commitment |
4186 | + if new_distrib_id: |
4187 | + self.pool.get('analytic.distribution').write(cr, uid, [new_distrib_id], |
4188 | + {'purchase_id': False, 'commitment_id': commit_id}, context=context) |
4189 | + # Create funding pool lines if needed |
4190 | + self.pool.get('analytic.distribution').create_funding_pool_lines(cr, uid, [new_distrib_id], context=context) |
4191 | + # Update commitment with new analytic distribution |
4192 | + self.pool.get('account.commitment').write(cr, uid, [commit_id], {'analytic_distribution_id': new_distrib_id}, context=context) |
4193 | + |
4194 | + return commit_id |
4195 | + |
4196 | purchase_order() |
4197 | |
4198 | -class purchase_order_line(osv.osv): |
4199 | - def _amount_line(self, cr, uid, ids, prop, arg, context=None): |
4200 | - res = {} |
4201 | - cur_obj=self.pool.get('res.currency') |
4202 | - tax_obj = self.pool.get('account.tax') |
4203 | - for line in self.browse(cr, uid, ids, context=context): |
4204 | - taxes = tax_obj.compute_all(cr, uid, line.taxes_id, line.price_unit, line.product_qty) |
4205 | - cur = line.order_id.pricelist_id.currency_id |
4206 | - res[line.id] = cur_obj.round(cr, uid, cur.rounding, taxes['total']) |
4207 | - if line.price_unit > 0 and res[line.id] < 0.01: |
4208 | - res[line.id] = 0.01 |
4209 | - return res |
4210 | - |
4211 | - def _get_stock_take_date(self, cr, uid, context=None): |
4212 | - ''' |
4213 | - Returns stock take date |
4214 | - ''' |
4215 | - if context is None: |
4216 | - context = {} |
4217 | - order_obj = self.pool.get('purchase.order') |
4218 | - res = False |
4219 | - |
4220 | - if context.get('purchase_id', False): |
4221 | - po = order_obj.browse(cr, uid, context.get('purchase_id'), context=context) |
4222 | - res = po.stock_take_date |
4223 | - |
4224 | - return res |
4225 | - |
4226 | - _columns = { |
4227 | - 'name': fields.char('Description', size=256, required=True), |
4228 | - 'product_qty': fields.float('Quantity', required=True, digits=(16,2)), |
4229 | - 'date_planned': fields.date('Scheduled Date', required=True, select=True), |
4230 | - 'taxes_id': fields.many2many('account.tax', 'purchase_order_taxe', 'ord_id', 'tax_id', 'Taxes'), |
4231 | - 'product_uom': fields.many2one('product.uom', 'Product UOM', required=True, select=True), |
4232 | - 'product_id': fields.many2one('product.product', 'Product', domain=[('purchase_ok','=',True)], change_default=True, select=True), |
4233 | - 'move_ids': fields.one2many('stock.move', 'purchase_line_id', 'Reservation', readonly=True, ondelete='set null'), |
4234 | - 'move_dest_id': fields.many2one('stock.move', 'Reservation Destination', ondelete='set null', select=True), |
4235 | - 'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Purchase Price')), |
4236 | - 'price_subtotal': fields.function(_amount_line, method=True, string='Subtotal', digits_compute= dp.get_precision('Purchase Price')), |
4237 | - 'notes': fields.text('Notes'), |
4238 | - 'order_id': fields.many2one('purchase.order', 'Order Reference', select=True, required=True, ondelete='cascade'), |
4239 | - 'account_analytic_id':fields.many2one('account.analytic.account', 'Analytic Account',), |
4240 | - 'company_id': fields.related('order_id','company_id',type='many2one',relation='res.company',string='Company', store=True, readonly=True), |
4241 | - 'state': fields.selection([('draft', 'Draft'), ('confirmed', 'Confirmed'), ('done', 'Done'), ('cancel', 'Cancelled')], 'State', required=True, readonly=True, |
4242 | - help=' * The \'Draft\' state is set automatically when purchase order in draft state. \ |
4243 | - \n* The \'Confirmed\' state is set automatically as confirm when purchase order in confirm state. \ |
4244 | - \n* The \'Done\' state is set automatically when purchase order is set as done. \ |
4245 | - \n* The \'Cancelled\' state is set automatically when user cancel purchase order.'), |
4246 | - 'invoice_lines': fields.many2many('account.invoice.line', 'purchase_order_line_invoice_rel', 'order_line_id', 'invoice_id', 'Invoice Lines', readonly=True), |
4247 | - 'invoiced': fields.boolean('Invoiced', readonly=True), |
4248 | - 'partner_id': fields.related('order_id','partner_id',string='Partner',readonly=True,type="many2one", relation="res.partner", store=True), |
4249 | - 'date_order': fields.related('order_id','date_order',string='Order Date',readonly=True,type="date"), |
4250 | - 'stock_take_date': fields.date(string='Date of Stock Take', required=False), |
4251 | - } |
4252 | - _defaults = { |
4253 | - 'product_qty': lambda *a: 1.0, |
4254 | - 'state': lambda *args: 'draft', |
4255 | - 'invoiced': lambda *a: 0, |
4256 | - 'stock_take_date': _get_stock_take_date, |
4257 | - } |
4258 | - _table = 'purchase_order_line' |
4259 | - _name = 'purchase.order.line' |
4260 | - _description = 'Purchase Order Line' |
4261 | - |
4262 | - def copy_data(self, cr, uid, id, default=None, context=None): |
4263 | - if not default: |
4264 | - default = {} |
4265 | - default.update({'state':'draft', 'move_ids':[],'invoiced':0,'invoice_lines':[]}) |
4266 | - return super(purchase_order_line, self).copy_data(cr, uid, id, default, context) |
4267 | - |
4268 | - def _hook_product_id_change(self, cr, uid, *args, **kwargs): |
4269 | - ''' |
4270 | - Override the computation of product qty to order |
4271 | - ''' |
4272 | - prod = kwargs['product'] |
4273 | - partner_id = kwargs['partner_id'] |
4274 | - qty = kwargs['product_qty'] |
4275 | - |
4276 | - product_uom_pool = self.pool.get('product.uom') |
4277 | - |
4278 | - res = {} |
4279 | - for s in prod.seller_ids: |
4280 | - if s.name.id == partner_id: |
4281 | - seller_delay = s.delay |
4282 | - if s.product_uom: |
4283 | - temp_qty = product_uom_pool._compute_qty(cr, uid, s.product_uom.id, s.min_qty, to_uom_id=prod.uom_id.id) |
4284 | - uom = s.product_uom.id #prod_uom_po |
4285 | - temp_qty = s.min_qty # supplier _qty assigned to temp |
4286 | - if qty < temp_qty: # If the supplier quantity is greater than entered from user, set minimal. |
4287 | - qty = temp_qty |
4288 | - res.update({'warning': {'title': _('Warning'), 'message': _('The selected supplier has a minimal quantity set to %s, you cannot purchase less.') % qty}}) |
4289 | - qty_in_product_uom = product_uom_pool._compute_qty(cr, uid, uom, qty, to_uom_id=prod.uom_id.id) |
4290 | - return res, qty_in_product_uom, qty, seller_delay |
4291 | - |
4292 | - |
4293 | - def product_id_change(self, cr, uid, ids, pricelist, product, qty, uom, |
4294 | - partner_id, date_order=False, fiscal_position=False, date_planned=False, |
4295 | - name=False, price_unit=False, notes=False): |
4296 | - if not pricelist: |
4297 | - raise osv.except_osv(_('No Pricelist !'), _('You have to select a pricelist or a supplier in the purchase form !\nPlease set one before choosing a product.')) |
4298 | - if not partner_id: |
4299 | - raise osv.except_osv(_('No Partner!'), _('You have to select a partner in the purchase form !\nPlease set one partner before choosing a product.')) |
4300 | - if not product: |
4301 | - return {'value': {'price_unit': price_unit or 0.0, 'name': name or '', |
4302 | - 'notes': notes or'', 'product_uom' : uom or False}, 'domain':{'product_uom':[]}} |
4303 | - res = {} |
4304 | - prod= self.pool.get('product.product').browse(cr, uid, product) |
4305 | - |
4306 | - lang=False |
4307 | - if partner_id: |
4308 | - lang=self.pool.get('res.partner').read(cr, uid, partner_id, ['lang'])['lang'] |
4309 | - context={'lang':lang} |
4310 | - context['partner_id'] = partner_id |
4311 | - |
4312 | - prod = self.pool.get('product.product').browse(cr, uid, product, context=context) |
4313 | - prod_uom_po = prod.uom_po_id.id |
4314 | - if not uom: |
4315 | - uom = prod_uom_po |
4316 | - if not date_order: |
4317 | - date_order = time.strftime('%Y-%m-%d') |
4318 | - qty = qty or 1.0 |
4319 | - seller_delay = 0 |
4320 | - |
4321 | - prod_name = self.pool.get('product.product').name_get(cr, uid, [prod.id], context=context)[0][1] |
4322 | - |
4323 | - res, qty_in_product_uom, qty, seller_delay = self._hook_product_id_change(cr, uid, product=prod, partner_id=partner_id, |
4324 | - product_qty=qty, pricelist=pricelist, order_date=date_order, uom_id=uom, |
4325 | - seller_delay=seller_delay, res=res, context=context) |
4326 | - |
4327 | - price = self.pool.get('product.pricelist').price_get(cr,uid,[pricelist], |
4328 | - product, qty_in_product_uom or 1.0, partner_id, { |
4329 | - 'uom': uom, |
4330 | - 'date': date_order, |
4331 | - })[pricelist] |
4332 | - if price is False: |
4333 | - warning = { |
4334 | - 'title': 'No valid pricelist line found !', |
4335 | - 'message': |
4336 | - "Couldn't find a pricelist line matching this product and quantity.\n" |
4337 | - "You have to change either the product, the quantity or the pricelist." |
4338 | - } |
4339 | - res.update({'warning': warning}) |
4340 | - dt = (datetime.now() + relativedelta(days=int(seller_delay) or 0.0)).strftime('%Y-%m-%d %H:%M:%S') |
4341 | - |
4342 | - |
4343 | - res.update({'value': {'price_unit': price, 'name': prod_name, |
4344 | - 'taxes_id':map(lambda x: x.id, prod.supplier_taxes_id), |
4345 | - 'date_planned': date_planned or dt,'notes': notes or prod.description_purchase, |
4346 | - 'product_qty': qty, |
4347 | - 'product_uom': uom}}) |
4348 | - domain = {} |
4349 | - |
4350 | - taxes = self.pool.get('account.tax').browse(cr, uid,map(lambda x: x.id, prod.supplier_taxes_id)) |
4351 | - fpos = fiscal_position and self.pool.get('account.fiscal.position').browse(cr, uid, fiscal_position) or False |
4352 | - res['value']['taxes_id'] = self.pool.get('account.fiscal.position').map_tax(cr, uid, fpos, taxes) |
4353 | - |
4354 | - res2 = self.pool.get('product.uom').read(cr, uid, [uom], ['category_id']) |
4355 | - res3 = prod.uom_id.category_id.id |
4356 | - domain = {'product_uom':[('category_id','=',res2[0]['category_id'][0])]} |
4357 | - if res2[0]['category_id'][0] != res3: |
4358 | - raise osv.except_osv(_('Wrong Product UOM !'), _('You have to select a product UOM in the same category than the purchase UOM of the product')) |
4359 | - |
4360 | - res['domain'] = domain |
4361 | - return res |
4362 | - |
4363 | - def product_uom_change(self, cr, uid, ids, pricelist, product, qty, uom, |
4364 | - partner_id, date_order=False, fiscal_position=False, date_planned=False, |
4365 | - name=False, price_unit=False, notes=False): |
4366 | - res = self.product_id_change(cr, uid, ids, pricelist, product, qty, uom, |
4367 | - partner_id, date_order=date_order, fiscal_position=fiscal_position, date_planned=date_planned, |
4368 | - name=name, price_unit=price_unit, notes=notes) |
4369 | - if 'product_uom' in res['value']: |
4370 | - if uom and (uom != res['value']['product_uom']) and res['value']['product_uom']: |
4371 | - seller_uom_name = self.pool.get('product.uom').read(cr, uid, [res['value']['product_uom']], ['name'])[0]['name'] |
4372 | - res.update({'warning': {'title': _('Warning'), 'message': _('The selected supplier only sells this product by %s') % seller_uom_name }}) |
4373 | - del res['value']['product_uom'] |
4374 | - if not uom: |
4375 | - res['value']['price_unit'] = 0.0 |
4376 | - return res |
4377 | - |
4378 | - def action_confirm(self, cr, uid, ids, context=None): |
4379 | - self.write(cr, uid, ids, {'state': 'confirmed'}, context=context) |
4380 | - return True |
4381 | - |
4382 | -purchase_order_line() |
4383 | - |
4384 | -class procurement_order(osv.osv): |
4385 | - _inherit = 'procurement.order' |
4386 | - _columns = { |
4387 | - 'purchase_id': fields.many2one('purchase.order', 'Purchase Order'), |
4388 | - } |
4389 | - |
4390 | - def action_po_assign(self, cr, uid, ids, context=None): |
4391 | - """ This is action which call from workflow to assign purchase order to procurements |
4392 | - @return: True |
4393 | - """ |
4394 | - res = self.make_po(cr, uid, ids, context=context) |
4395 | - res = res.values() |
4396 | - return len(res) and res[0] or 0 #TO CHECK: why workflow is generated error if return not integer value |
4397 | - |
4398 | - def get_partner_hook(self, cr, uid, ids, context=None, *args, **kwargs): |
4399 | - ''' |
4400 | - return a dictionary with partner, seller_qty and seller_delay |
4401 | - ''' |
4402 | - result = {} |
4403 | - |
4404 | - procurement = kwargs['procurement'] |
4405 | - partner = procurement.product_id.seller_id # Taken Main Supplier of Product of Procurement. |
4406 | - seller_qty = procurement.product_id.seller_qty |
4407 | - seller_delay = int(procurement.product_id.seller_delay) |
4408 | - |
4409 | - result.update(partner=partner, |
4410 | - seller_qty=seller_qty, |
4411 | - seller_delay=seller_delay) |
4412 | - |
4413 | - return result |
4414 | - |
4415 | - def po_line_values_hook(self, cr, uid, ids, context=None, *args, **kwargs): |
4416 | - ''' |
4417 | - Please copy this to your module's method also. |
4418 | - This hook belongs to the make_po method from purchase>purchase.py>procurement_order |
4419 | - |
4420 | - - allow to modify the data for purchase order line creation |
4421 | - ''' |
4422 | - line = kwargs['line'] |
4423 | - return line |
4424 | - |
4425 | - def po_values_hook(self, cr, uid, ids, context=None, *args, **kwargs): |
4426 | - ''' |
4427 | - Please copy this to your module's method also. |
4428 | - This hook belongs to the make_po method from purchase>purchase.py>procurement_order |
4429 | - |
4430 | - - allow to modify the data for purchase order creation |
4431 | - ''' |
4432 | - values = kwargs['values'] |
4433 | - return values |
4434 | - |
4435 | - def create_po_hook(self, cr, uid, ids, context=None, *args, **kwargs): |
4436 | - ''' |
4437 | - creation of purchase order |
4438 | - return the id of newly created po |
4439 | - ''' |
4440 | - po_obj = self.pool.get('purchase.order') |
4441 | - values = kwargs['values'] |
4442 | - purchase_id = po_obj.create(cr, uid, values, context=context) |
4443 | - return purchase_id |
4444 | - |
4445 | - def make_po(self, cr, uid, ids, context=None): |
4446 | - """ Make purchase order from procurement |
4447 | - @return: New created Purchase Orders procurement wise |
4448 | - """ |
4449 | - res = {} |
4450 | - if context is None: |
4451 | - context = {} |
4452 | - company = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id |
4453 | - partner_obj = self.pool.get('res.partner') |
4454 | - uom_obj = self.pool.get('product.uom') |
4455 | - pricelist_obj = self.pool.get('product.pricelist') |
4456 | - prod_obj = self.pool.get('product.product') |
4457 | - acc_pos_obj = self.pool.get('account.fiscal.position') |
4458 | - for procurement in self.browse(cr, uid, ids, context=context): |
4459 | - res_id = procurement.move_id.id |
4460 | - |
4461 | - # partner, seller_qty and seller_delay are computed with hook |
4462 | - hook = self.get_partner_hook(cr, uid, ids, context=context, procurement=procurement) |
4463 | - partner = hook['partner'] |
4464 | - seller_qty = hook['seller_qty'] |
4465 | - seller_delay = hook['seller_delay'] |
4466 | - partner_id = partner.id |
4467 | - address_id = partner_obj.address_get(cr, uid, [partner_id], ['delivery'])['delivery'] |
4468 | - pricelist_id = partner.property_product_pricelist_purchase |
4469 | - |
4470 | - uom_id = procurement.product_id.uom_po_id.id |
4471 | - |
4472 | - qty = uom_obj._compute_qty(cr, uid, procurement.product_uom.id, procurement.product_qty, uom_id) |
4473 | - if seller_qty: |
4474 | - qty = max(qty,seller_qty) |
4475 | - |
4476 | - price = pricelist_obj.price_get(cr, uid, [pricelist_id.id], procurement.product_id.id, qty, partner_id, {'uom': uom_id})[pricelist_id.id] |
4477 | - if hook.get('price_unit', False): |
4478 | - price = hook.get('price_unit', False) |
4479 | - |
4480 | - newdate = datetime.strptime(procurement.date_planned, '%Y-%m-%d %H:%M:%S') |
4481 | - newdate = (newdate - relativedelta(days=int(company.po_lead))) - relativedelta(days=int(seller_delay)) |
4482 | - |
4483 | - #Passing partner_id to context for purchase order line integrity of Line name |
4484 | - context.update({'lang': partner.lang, 'partner_id': partner_id}) |
4485 | - |
4486 | - product = prod_obj.browse(cr, uid, procurement.product_id.id, context=context) |
4487 | - |
4488 | - line = { |
4489 | - 'name': product.partner_ref, |
4490 | - 'product_qty': qty, |
4491 | - 'product_id': procurement.product_id.id, |
4492 | - 'product_uom': uom_id, |
4493 | - 'price_unit': price, |
4494 | - 'date_planned': newdate.strftime('%Y-%m-%d %H:%M:%S'), |
4495 | - 'move_dest_id': res_id, |
4496 | - 'notes': product.description_purchase, |
4497 | - } |
4498 | - |
4499 | - # line values modification from hook |
4500 | - line = self.po_line_values_hook(cr, uid, ids, context=context, line=line, procurement=procurement, pricelist=pricelist_id) |
4501 | - |
4502 | - taxes_ids = procurement.product_id.product_tmpl_id.supplier_taxes_id |
4503 | - taxes = acc_pos_obj.map_tax(cr, uid, partner.property_account_position, taxes_ids) |
4504 | - line.update({ |
4505 | - 'taxes_id': [(6,0,taxes)] |
4506 | - }) |
4507 | - values = { |
4508 | - 'origin': procurement.origin, |
4509 | - 'partner_id': partner_id, |
4510 | - 'partner_address_id': address_id, |
4511 | - 'location_id': procurement.location_id.id, |
4512 | - 'pricelist_id': pricelist_id.id, |
4513 | - 'order_line': [(0,0,line)], |
4514 | - 'company_id': procurement.company_id.id, |
4515 | - 'fiscal_position': partner.property_account_position and partner.property_account_position.id or False, |
4516 | - } |
4517 | - # values modification from hook |
4518 | - values = self.po_values_hook(cr, uid, ids, context=context, values=values, procurement=procurement, line=line,) |
4519 | - # purchase creation from hook |
4520 | - purchase_id = self.create_po_hook(cr, uid, ids, context=context, values=values, procurement=procurement) |
4521 | - res[procurement.id] = purchase_id |
4522 | - self.write(cr, uid, [procurement.id], {'state': 'running', 'purchase_id': purchase_id}) |
4523 | - return res |
4524 | - |
4525 | -procurement_order() |
4526 | |
4527 | class stock_invoice_onshipping(osv.osv_memory): |
4528 | _inherit = "stock.invoice.onshipping" |
4529 | |
4530 | === modified file 'bin/addons/purchase/purchase_data.xml' |
4531 | --- bin/addons/purchase/purchase_data.xml 2011-01-14 00:11:01 +0000 |
4532 | +++ bin/addons/purchase/purchase_data.xml 2017-10-02 12:34:11 +0000 |
4533 | @@ -1,7 +1,6 @@ |
4534 | <?xml version="1.0" encoding="utf-8"?> |
4535 | <openerp> |
4536 | <data noupdate="1"> |
4537 | - |
4538 | <record id="req_link_purchase_order" model="res.request.link"> |
4539 | <field name="name">Purchase Order</field> |
4540 | <field name="object">purchase.order</field> |
4541 | @@ -37,6 +36,48 @@ |
4542 | id="purchase_default_set" |
4543 | model="ir.values" |
4544 | name="set"/> |
4545 | - |
4546 | + </data> |
4547 | + |
4548 | + <data noupdate="0"> |
4549 | + <record id="pol_state_cancel" model="purchase.order.line.state"> |
4550 | + <field name="name">cancel</field> |
4551 | + <field name="sequence">1000</field> |
4552 | + </record> |
4553 | + <record id="pol_state_cancel_r" model="purchase.order.line.state"> |
4554 | + <field name="name">cancel_r</field> |
4555 | + <field name="sequence">1001</field> |
4556 | + </record> |
4557 | + <record id="pol_state_draft" model="purchase.order.line.state"> |
4558 | + <field name="name">draft</field> |
4559 | + <field name="sequence">10</field> |
4560 | + </record> |
4561 | + <record id="pol_state_validated_n" model="purchase.order.line.state"> |
4562 | + <field name="name">validated_n</field> |
4563 | + <field name="sequence">15</field> |
4564 | + </record> |
4565 | + <record id="pol_state_validated" model="purchase.order.line.state"> |
4566 | + <field name="name">validated</field> |
4567 | + <field name="sequence">20</field> |
4568 | + </record> |
4569 | + <record id="pol_state_sourced_sy" model="purchase.order.line.state"> |
4570 | + <field name="name">sourced_sy</field> |
4571 | + <field name="sequence">40</field> |
4572 | + </record> |
4573 | + <record id="pol_state_sourced_v" model="purchase.order.line.state"> |
4574 | + <field name="name">sourced_v</field> |
4575 | + <field name="sequence">50</field> |
4576 | + </record> |
4577 | + <record id="pol_state_sourced_n" model="purchase.order.line.state"> |
4578 | + <field name="name">sourced_n</field> |
4579 | + <field name="sequence">60</field> |
4580 | + </record> |
4581 | + <record id="pol_state_confirmed" model="purchase.order.line.state"> |
4582 | + <field name="name">confirmed</field> |
4583 | + <field name="sequence">70</field> |
4584 | + </record> |
4585 | + <record id="pol_state_done" model="purchase.order.line.state"> |
4586 | + <field name="name">done</field> |
4587 | + <field name="sequence">80</field> |
4588 | + </record> |
4589 | </data> |
4590 | </openerp> |
4591 | |
4592 | === added file 'bin/addons/purchase/purchase_line.py' |
4593 | --- bin/addons/purchase/purchase_line.py 1970-01-01 00:00:00 +0000 |
4594 | +++ bin/addons/purchase/purchase_line.py 2017-10-02 12:34:11 +0000 |
4595 | @@ -0,0 +1,1422 @@ |
4596 | +# -*- coding: utf-8 -*- |
4597 | + |
4598 | +import time |
4599 | +from datetime import datetime |
4600 | +from dateutil.relativedelta import relativedelta |
4601 | + |
4602 | +from osv import osv, fields |
4603 | +from tools.translate import _ |
4604 | +import decimal_precision as dp |
4605 | +from purchase_override import PURCHASE_ORDER_STATE_SELECTION, PURCHASE_ORDER_LINE_STATE_SELECTION |
4606 | + |
4607 | + |
4608 | +class purchase_order_line(osv.osv): |
4609 | + _table = 'purchase_order_line' |
4610 | + _name = 'purchase.order.line' |
4611 | + _description = 'Purchase Order Line' |
4612 | + |
4613 | + def _get_vat_ok(self, cr, uid, ids, field_name, args, context=None): |
4614 | + ''' |
4615 | + Return True if the system configuration VAT management is set to True |
4616 | + ''' |
4617 | + vat_ok = self.pool.get('unifield.setup.configuration').get_config(cr, uid).vat_ok |
4618 | + res = {} |
4619 | + for id in ids: |
4620 | + res[id] = vat_ok |
4621 | + |
4622 | + return res |
4623 | + |
4624 | + def _amount_line(self, cr, uid, ids, prop, arg, context=None): |
4625 | + res = {} |
4626 | + cur_obj = self.pool.get('res.currency') |
4627 | + tax_obj = self.pool.get('account.tax') |
4628 | + for line in self.browse(cr, uid, ids, context=context): |
4629 | + taxes = tax_obj.compute_all(cr, uid, line.taxes_id, line.price_unit, line.product_qty) |
4630 | + cur = line.order_id.pricelist_id.currency_id |
4631 | + res[line.id] = cur_obj.round(cr, uid, cur.rounding, taxes['total']) |
4632 | + if line.price_unit > 0 and res[line.id] < 0.01: |
4633 | + res[line.id] = 0.01 |
4634 | + return res |
4635 | + |
4636 | + def _get_price_change_ok(self, cr, uid, ids, field_name, args, context=None): |
4637 | + ''' |
4638 | + Returns True if the price can be changed by the user |
4639 | + ''' |
4640 | + res = {} |
4641 | + |
4642 | + for line in self.browse(cr, uid, ids, context=context): |
4643 | + res[line.id] = True |
4644 | + stages = self._get_stages_price(cr, uid, line.product_id.id, line.product_uom.id, line.order_id, |
4645 | + context=context) |
4646 | + if line.merged_id and len( |
4647 | + line.merged_id.order_line_ids) > 1 and line.order_id.state != 'confirmed' and stages and not line.order_id.rfq_ok: |
4648 | + res[line.id] = False |
4649 | + |
4650 | + return res |
4651 | + |
4652 | + def _get_fake_state(self, cr, uid, ids, field_name, args, context=None): |
4653 | + if isinstance(ids, (int, long)): |
4654 | + ids = [ids] |
4655 | + ret = {} |
4656 | + for pol in self.read(cr, uid, ids, ['state']): |
4657 | + ret[pol['id']] = pol['state'] |
4658 | + return ret |
4659 | + |
4660 | + def _get_fake_id(self, cr, uid, ids, field_name, args, context=None): |
4661 | + if isinstance(ids, (int, long)): |
4662 | + ids = [ids] |
4663 | + ret = {} |
4664 | + for pol in self.read(cr, uid, ids, ['id']): |
4665 | + ret[pol['id']] = pol['id'] |
4666 | + return ret |
4667 | + |
4668 | + def _vals_get(self, cr, uid, ids, fields, arg, context=None): |
4669 | + ''' |
4670 | + multi fields function method |
4671 | + ''' |
4672 | + # Some verifications |
4673 | + if context is None: |
4674 | + context = {} |
4675 | + if isinstance(ids, (int, long)): |
4676 | + ids = [ids] |
4677 | + |
4678 | + result = {} |
4679 | + for obj in self.browse(cr, uid, ids, context=context): |
4680 | + # default values |
4681 | + result[obj.id] = {'order_state_purchase_order_line': False} |
4682 | + # order_state_purchase_order_line |
4683 | + if obj.order_id: |
4684 | + result[obj.id].update({'order_state_purchase_order_line': obj.order_id.state}) |
4685 | + |
4686 | + return result |
4687 | + |
4688 | + def _get_project_po_ref(self, cr, uid, ids, field_name, args, context=None): |
4689 | + ''' |
4690 | + Return the name of the PO at project side |
4691 | + ''' |
4692 | + if isinstance(ids, (int, long)): |
4693 | + ids = [ids] |
4694 | + |
4695 | + res = dict.fromkeys(ids, '') |
4696 | + for line_id in ids: |
4697 | + sol_ids = self.get_sol_ids_from_pol_ids(cr, uid, line_id, context=context) |
4698 | + for sol in self.pool.get('sale.order.line').browse(cr, uid, sol_ids, context=context): |
4699 | + if sol.order_id and sol.order_id.client_order_ref: |
4700 | + if res[line_id]: |
4701 | + res[line_id] += ' - ' |
4702 | + res[line_id] += sol.order_id.client_order_ref |
4703 | + |
4704 | + return res |
4705 | + |
4706 | + def _get_link_sol_id(self, cr, uid, ids, field_name, args, context=None): |
4707 | + """ |
4708 | + Return the ID of the first FO line sourced by this PO line |
4709 | + """ |
4710 | + if isinstance(ids, (int, long)): |
4711 | + ids = [ids] |
4712 | + |
4713 | + res = dict.fromkeys(ids, False) |
4714 | + for line_id in ids: |
4715 | + sol_ids = self.get_sol_ids_from_pol_ids(cr, uid, [line_id], context=context) |
4716 | + if sol_ids: |
4717 | + res[line_id] = sol_ids[0] |
4718 | + |
4719 | + return res |
4720 | + |
4721 | + def _get_customer_ref(self, cr, uid, ids, field_name, args, context=None): |
4722 | + ''' |
4723 | + Return the customer ref from "sale.order".client_order_ref |
4724 | + ''' |
4725 | + if isinstance(ids, (int, long)): |
4726 | + ids = [ids] |
4727 | + |
4728 | + res = {} |
4729 | + for pol in self.browse(cr, uid, ids, context=context): |
4730 | + res[ |
4731 | + pol.id] = pol.linked_sol_id and pol.linked_sol_id.order_id.client_order_ref or False |
4732 | + |
4733 | + return res |
4734 | + |
4735 | + def _get_state_to_display(self, cr, uid, ids, field_name, args, context=None): |
4736 | + ''' |
4737 | + return the purchase.order.line state to display |
4738 | + ''' |
4739 | + if context is None: |
4740 | + context = {} |
4741 | + if isinstance(ids, (int,long)): |
4742 | + ids = [ids] |
4743 | + |
4744 | + res = {} |
4745 | + for pol in self.browse(cr, uid, ids, context=context): |
4746 | + # if PO line has been created from ressourced process, then we display the state as 'Resourced-XXX' (excepted for 'done' status) |
4747 | + if pol.resourced_original_line and pol.state != 'done': |
4748 | + if pol.state.startswith('validated'): |
4749 | + res[pol.id] = 'Resourced-v' |
4750 | + elif pol.state.startswith('sourced'): |
4751 | + if pol.state == 'sourced_v': |
4752 | + res[pol.id] = 'Resourced-pv' |
4753 | + elif pol.state == 'sourced_sy': |
4754 | + res[pol.id] = 'Resourced-sy' |
4755 | + else: |
4756 | + res[pol.id] = 'Resourced-s' |
4757 | + elif pol.state.startswith('confirmed'): |
4758 | + res[pol.id] = 'Resourced-c' |
4759 | + else: # draft + unexpected PO line state |
4760 | + res[pol.id] = 'Resourced-d' |
4761 | + else: # state_to_display == state |
4762 | + res[pol.id] = self.pool.get('ir.model.fields').get_browse_selection(cr, uid, pol, 'state', context=context) |
4763 | + |
4764 | + return res |
4765 | + |
4766 | + |
4767 | + def _get_display_resourced_orig_line(self, cr, uid, ids, field_name, args, context=None): |
4768 | + ''' |
4769 | + return the original PO line (from which the current one has been resourced) formatted as wanted |
4770 | + ''' |
4771 | + if context is None: |
4772 | + context = {} |
4773 | + if isinstance(ids, (int,long)): |
4774 | + ids = [ids] |
4775 | + |
4776 | + res = {} |
4777 | + for pol in self.browse(cr, uid, ids, context=context): |
4778 | + res[pol.id] = False |
4779 | + if pol.resourced_original_line: |
4780 | + res[pol.id] = '%s' % (pol.resourced_original_line.line_number) |
4781 | + |
4782 | + return res |
4783 | + |
4784 | + def _get_stock_take_date(self, cr, uid, context=None): |
4785 | + ''' |
4786 | + Returns stock take date |
4787 | + ''' |
4788 | + if context is None: |
4789 | + context = {} |
4790 | + order_obj = self.pool.get('purchase.order') |
4791 | + res = False |
4792 | + |
4793 | + if context.get('purchase_id', False): |
4794 | + po = order_obj.browse(cr, uid, context.get('purchase_id'), context=context) |
4795 | + res = po.stock_take_date |
4796 | + |
4797 | + return res |
4798 | + |
4799 | + |
4800 | + _columns = { |
4801 | + 'set_as_sourced_n': fields.boolean(string='Set as Sourced-n', help='Line has been created further and has to be created back in preceding documents'), |
4802 | + 'set_as_validated_n': fields.boolean(string='Created when PO validated', help='Usefull for workflow transition to set the validated-n state'), |
4803 | + 'is_line_split': fields.boolean(string='This line is a split line?'), |
4804 | + 'linked_sol_id': fields.many2one('sale.order.line', string='Linked FO line', help='Linked Sale Order line in case of PO line from sourcing', readonly=True), |
4805 | + 'sync_linked_sol': fields.char(size=256, string='Linked FO line at synchro'), |
4806 | + # UTP-972: Use boolean to indicate if the line is a split line |
4807 | + 'merged_id': fields.many2one('purchase.order.merged.line', string='Merged line'), |
4808 | + 'origin': fields.char(size=512, string='Origin'), |
4809 | + 'link_so_id': fields.many2one('sale.order', string='Linked FO/IR', readonly=True), |
4810 | + 'dpo_received': fields.boolean(string='Is the IN has been received at Project side ?'), |
4811 | + 'change_price_ok': fields.function(_get_price_change_ok, type='boolean', method=True, string='Price changing'), |
4812 | + 'change_price_manually': fields.boolean(string='Update price manually'), |
4813 | + # openerp bug: eval invisible in p.o use the po line state and not the po state ! |
4814 | + 'fake_state': fields.function(_get_fake_state, type='char', method=True, string='State', |
4815 | + help='for internal use only'), |
4816 | + # openerp bug: id is not given to onchanqge call if we are into one2many view |
4817 | + 'fake_id': fields.function(_get_fake_id, type='integer', method=True, string='Id', |
4818 | + help='for internal use only'), |
4819 | + 'old_price_unit': fields.float(string='Old price', |
4820 | + digits_compute=dp.get_precision('Purchase Price Computation')), |
4821 | + 'order_state_purchase_order_line': fields.function(_vals_get, method=True, type='selection', |
4822 | + selection=PURCHASE_ORDER_STATE_SELECTION, |
4823 | + string='State of Po', multi='get_vals_purchase_override', |
4824 | + store=False, readonly=True), |
4825 | + |
4826 | + # This field is used to identify the FO PO line between 2 instances of the sync |
4827 | + 'sync_order_line_db_id': fields.text(string='Sync order line DB Id', required=False, readonly=True), |
4828 | + 'external_ref': fields.char(size=256, string='Ext. Ref.'), |
4829 | + 'project_ref': fields.char(size=256, string='Project Ref.'), |
4830 | + 'has_to_be_resourced': fields.boolean(string='Has to be re-sourced'), |
4831 | + 'select_fo': fields.many2one('sale.order', string='FO'), |
4832 | + 'fnct_project_ref': fields.function(_get_project_po_ref, method=True, string='Project PO', |
4833 | + type='char', size=128, store=False), |
4834 | + 'from_fo': fields.boolean(string='From FO', readonly=True), |
4835 | + 'display_sync_ref': fields.boolean(string='Display sync. ref.'), |
4836 | + 'instance_sync_order_ref': fields.many2one('sync.order.label', string='Order in sync. instance'), |
4837 | + 'link_sol_id': fields.function(_get_link_sol_id, method=True, type='many2one', relation='sale.order.line', |
4838 | + string='Linked FO line', store=False), |
4839 | + 'soq_updated': fields.boolean(string='SoQ updated', readonly=True), |
4840 | + 'red_color': fields.boolean(string='Red color'), |
4841 | + 'customer_ref': fields.function(_get_customer_ref, method=True, type="text", store=False, |
4842 | + string="Customer ref."), |
4843 | + 'name': fields.char('Description', size=256, required=True), |
4844 | + 'product_qty': fields.float('Quantity', required=True, digits=(16, 2)), |
4845 | + 'date_planned': fields.date('Scheduled Date', required=True, select=True), |
4846 | + 'taxes_id': fields.many2many('account.tax', 'purchase_order_taxe', 'ord_id', 'tax_id', 'Taxes'), |
4847 | + 'product_uom': fields.many2one('product.uom', 'Product UOM', required=True, select=True), |
4848 | + 'product_id': fields.many2one('product.product', 'Product', domain=[('purchase_ok', '=', True)], |
4849 | + change_default=True, select=True), |
4850 | + 'move_ids': fields.one2many('stock.move', 'purchase_line_id', 'Reservation', readonly=True, |
4851 | + ondelete='set null'), |
4852 | + 'move_dest_id': fields.many2one('stock.move', 'Reservation Destination', ondelete='set null', select=True), |
4853 | + 'price_unit': fields.float('Unit Price', required=True, |
4854 | + digits_compute=dp.get_precision('Purchase Price Computation')), |
4855 | + 'vat_ok': fields.function(_get_vat_ok, method=True, type='boolean', string='VAT OK', store=False, |
4856 | + readonly=True), |
4857 | + 'price_subtotal': fields.function(_amount_line, method=True, string='Subtotal', |
4858 | + digits_compute=dp.get_precision('Purchase Price')), |
4859 | + 'notes': fields.text('Notes'), |
4860 | + 'order_id': fields.many2one('purchase.order', 'Order Reference', select=True, required=True, |
4861 | + ondelete='cascade'), |
4862 | + 'account_analytic_id': fields.many2one('account.analytic.account', 'Analytic Account', ), |
4863 | + 'company_id': fields.related('order_id', 'company_id', type='many2one', relation='res.company', |
4864 | + string='Company', store=True, readonly=True), |
4865 | + 'state': fields.selection(PURCHASE_ORDER_LINE_STATE_SELECTION, 'State', required=True, readonly=True, |
4866 | + help=' * The \'Draft\' state is set automatically when purchase order in draft state. \ |
4867 | + \n* The \'Confirmed\' state is set automatically as confirm when purchase order in confirm state. \ |
4868 | + \n* The \'Done\' state is set automatically when purchase order is set as done. \ |
4869 | + \n* The \'Cancelled\' state is set automatically when user cancel purchase order.'), |
4870 | + 'state_to_display': fields.function(_get_state_to_display, string='State', type='text', method=True, readonly=True, |
4871 | + help=' * The \'Draft\' state is set automatically when purchase order in draft state. \ |
4872 | + \n* The \'Confirmed\' state is set automatically as confirm when purchase order in confirm state. \ |
4873 | + \n* The \'Done\' state is set automatically when purchase order is set as done. \ |
4874 | + \n* The \'Cancelled\' state is set automatically when user cancel purchase order.' |
4875 | + ), |
4876 | + 'resourced_original_line': fields.many2one('purchase.order.line', 'Original line', readonly=True, help='Original line from which the current one has been cancel and ressourced'), |
4877 | + 'display_resourced_orig_line': fields.function(_get_display_resourced_orig_line, method=True, type='char', readonly=True, string='Original PO line', help='Original line from which the current one has been cancel and ressourced'), |
4878 | + 'invoice_lines': fields.many2many('account.invoice.line', 'purchase_order_line_invoice_rel', 'order_line_id', |
4879 | + 'invoice_id', 'Invoice Lines', readonly=True), |
4880 | + 'invoiced': fields.boolean('Invoiced', readonly=True), |
4881 | + 'partner_id': fields.related('order_id','partner_id',string='Partner',readonly=True,type="many2one", relation="res.partner", store=True), |
4882 | + 'date_order': fields.related('order_id','date_order',string='Order Date',readonly=True,type="date"), |
4883 | + 'stock_take_date': fields.date(string='Date of Stock Take', required=False), |
4884 | + } |
4885 | + _defaults = { |
4886 | + 'set_as_sourced_n': lambda *a: False, |
4887 | + 'set_as_validated_n': lambda *a: False, |
4888 | + 'change_price_manually': lambda *a: False, |
4889 | + 'product_qty': lambda *a: 0.00, |
4890 | + 'price_unit': lambda *a: 0.00, |
4891 | + 'change_price_ok': lambda *a: True, |
4892 | + 'is_line_split': False, # UTP-972: by default not a split line |
4893 | + 'from_fo': lambda self, cr, uid, c: not c.get('rfq_ok', False) and c.get('from_fo', False), |
4894 | + 'soq_updated': False, |
4895 | + 'state': lambda *args: 'draft', |
4896 | + 'invoiced': lambda *a: 0, |
4897 | + 'vat_ok': lambda obj, cr, uid, context: obj.pool.get('unifield.setup.configuration').get_config(cr, uid).vat_ok, |
4898 | + 'stock_take_date': _get_stock_take_date, |
4899 | + } |
4900 | + |
4901 | + def _get_destination_ok(self, cr, uid, lines, context): |
4902 | + dest_ok = False |
4903 | + for line in lines: |
4904 | + is_inkind = line.order_id and line.order_id.order_type == 'in_kind' or False |
4905 | + dest_ok = line.account_4_distribution and line.account_4_distribution.destination_ids or False |
4906 | + if not dest_ok: |
4907 | + if is_inkind: |
4908 | + raise osv.except_osv(_('Error'), _( |
4909 | + 'No destination found. An In-kind Donation account is probably missing for this line: %s.') % ( |
4910 | + line.name or '')) |
4911 | + raise osv.except_osv(_('Error'), _('No destination found for this line: %s.') % (line.name or '',)) |
4912 | + return dest_ok |
4913 | + |
4914 | + def check_analytic_distribution(self, cr, uid, ids, context=None, create_missing=False): |
4915 | + """ |
4916 | + Check analytic distribution validity for given PO line. |
4917 | + Also check that partner have a donation account (is PO is in_kind) |
4918 | + """ |
4919 | + # Objects |
4920 | + ad_obj = self.pool.get('analytic.distribution') |
4921 | + ccdl_obj = self.pool.get('cost.center.distribution.line') |
4922 | + pol_obj = self.pool.get('purchase.order.line') |
4923 | + imd_obj = self.pool.get('ir.model.data') |
4924 | + |
4925 | + if context is None: |
4926 | + context = {} |
4927 | + if isinstance(ids, (int, long)): |
4928 | + ids = [ids] |
4929 | + |
4930 | + try: |
4931 | + intermission_cc = imd_obj.get_object_reference(cr, uid, 'analytic_distribution', 'analytic_account_project_intermission')[1] |
4932 | + except ValueError: |
4933 | + intermission_cc = 0 |
4934 | + |
4935 | + po_info = {} |
4936 | + for pol in self.browse(cr, uid, ids, context=context): |
4937 | + po = pol.order_id |
4938 | + if po.id not in po_info: |
4939 | + donation_intersection = po.order_type in ['donation_exp', 'donation_st'] and po.partner_type and po.partner_type == 'section' |
4940 | + if po.order_type == 'in_kind' or donation_intersection: |
4941 | + if not po.partner_id.donation_payable_account: |
4942 | + raise osv.except_osv(_('Error'), _('No donation account on this partner: %s') % (po.partner_id.name or '',)) |
4943 | + |
4944 | + if po.partner_id and po.partner_id.partner_type == 'intermission': |
4945 | + if not intermission_cc: |
4946 | + raise osv.except_osv(_('Error'), _('No Intermission Cost Center found!')) |
4947 | + |
4948 | + po_info[po.id] = True |
4949 | + |
4950 | + |
4951 | + distrib = pol.analytic_distribution_id or po.analytic_distribution_id or False |
4952 | + |
4953 | + |
4954 | + # Raise an error if no analytic distribution found |
4955 | + if not distrib: |
4956 | + # UFTP-336: For the case of a new line added from Coordo, it's a push flow, no need to check the AD! VERY SPECIAL CASE |
4957 | + if po.order_type not in ('loan', 'donation_st', 'donation_exp', 'in_kind') or po.push_fo: |
4958 | + return True |
4959 | + if create_missing and po.partner_id and po.partner_id.partner_type == 'intermission': |
4960 | + # intermission push flow, new line added: AD needed |
4961 | + destination_id = pol.account_4_distribution and pol.account_4_distribution.default_destination_id and pol.account_4_distribution.default_destination_id.id or False |
4962 | + ad_obj.create(cr, uid, { |
4963 | + 'purchase_line_ids': [(4, pol.id)], |
4964 | + 'cost_center_lines': [(0, 0, {'destination_id': destination_id, 'analytic_id': intermission_cc , 'percentage':'100', 'currency_id': po.currency_id.id})] |
4965 | + }) |
4966 | + else: |
4967 | + raise osv.except_osv(_('Warning'), |
4968 | + _('Analytic allocation is mandatory for this line: %s!') % (pol.name or '',)) |
4969 | + |
4970 | + elif pol.analytic_distribution_state != 'valid': |
4971 | + id_ad = ad_obj.create(cr, uid, {}) |
4972 | + ad_lines = pol.analytic_distribution_id and pol.analytic_distribution_id.cost_center_lines or po.analytic_distribution_id.cost_center_lines |
4973 | + bro_dests = self._get_destination_ok(cr, uid, [pol], context=context) |
4974 | + for line in ad_lines: |
4975 | + # fetch compatible destinations then use on of them: |
4976 | + # - destination if compatible |
4977 | + # - else default destination of given account |
4978 | + if line.destination_id in bro_dests: |
4979 | + bro_dest_ok = line.destination_id |
4980 | + else: |
4981 | + bro_dest_ok = pol.account_4_distribution.default_destination_id |
4982 | + # Copy cost center line to the new distribution |
4983 | + ccdl_obj.copy(cr, uid, line.id, { |
4984 | + 'distribution_id': id_ad, |
4985 | + 'destination_id': bro_dest_ok.id, |
4986 | + 'partner_type': po.partner_id.partner_type, |
4987 | + }) |
4988 | + # Write result |
4989 | + pol_obj.write(cr, uid, [pol.id], {'analytic_distribution_id': id_ad}) |
4990 | + else: |
4991 | + ad_lines = pol.analytic_distribution_id and pol.analytic_distribution_id.cost_center_lines or po.analytic_distribution_id.cost_center_lines |
4992 | + line_ids_to_write = [line.id for line in ad_lines if not |
4993 | + line.partner_type] |
4994 | + ccdl_obj.write(cr, uid, line_ids_to_write, { |
4995 | + 'partner_type': pol.order_id.partner_id.partner_type, |
4996 | + }) |
4997 | + |
4998 | + return True |
4999 | + |
5000 | + def _hook_product_id_change(self, cr, uid, *args, **kwargs): |
The diff has been truncated for viewing.