Merge lp:~unifield-team/unifield-addons/new-purchase-order-state into lp:unifield-addons

Proposed by Quentin THEURET @Amaris
Status: Merged
Merged at revision: 4457
Proposed branch: lp:~unifield-team/unifield-addons/new-purchase-order-state
Merge into: lp:unifield-addons
Diff against target: 1069 lines (+996/-0)
14 files modified
procurement_list/__init__.py (+25/-0)
procurement_list/__openerp__.py (+53/-0)
procurement_list/procurement_list.py (+217/-0)
procurement_list/procurement_list_sequence.xml (+20/-0)
procurement_list/procurement_list_view.xml (+111/-0)
procurement_list/procurement_list_wizard.xml (+21/-0)
procurement_list/security/ir.model.access.csv (+3/-0)
procurement_list/test/list_import.csv (+5/-0)
procurement_list/test/procurement_list.yml (+143/-0)
procurement_list/wizard/__init__.py (+28/-0)
procurement_list/wizard/wizard_import_list.py (+196/-0)
procurement_list/wizard/wizard_import_list_view.xml (+48/-0)
procurement_list/wizard/wizard_list_to_order.py (+63/-0)
procurement_list/wizard/wizard_list_to_rfq.py (+63/-0)
To merge this branch: bzr merge lp:~unifield-team/unifield-addons/new-purchase-order-state
Reviewer Review Type Date Requested Status
UniField Dev Team Pending
Review via email: mp+53577@code.launchpad.net
To post a comment you must log in.
4469. By Quentin THEURET @Amaris

UF-98: [FIX] Fixed bug on confirmation of a purchase order with a line which hasn't linked procurement list line

4470. By Quentin THEURET @Amaris

UF-98: [ADD] Added csv file for import test

4471. By Quentin THEURET <quentin@tempo-quentin>

UF-98: [IMP] Added copy method to procurement.list to increase sequence and set empty the latest field of lines

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added directory 'procurement_list'
=== added file 'procurement_list/__init__.py'
--- procurement_list/__init__.py 1970-01-01 00:00:00 +0000
+++ procurement_list/__init__.py 2011-03-16 16:41:25 +0000
@@ -0,0 +1,25 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21
22import procurement_list
23import wizard
24
25# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
026
=== added file 'procurement_list/__openerp__.py'
--- procurement_list/__openerp__.py 1970-01-01 00:00:00 +0000
+++ procurement_list/__openerp__.py 2011-03-16 16:41:25 +0000
@@ -0,0 +1,53 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21{
22 'name' : 'Purchase list',
23 'version' : '1.0',
24 'author' : 'TeMPO Consulting, MSF',
25 'category': 'Generic Modules/Sales & Purchases',
26 'description': '''
27 This module allows you to create a list of items to procure. You can create automatically RfQ for these lists after choosing a list \
28 of suppliers. You can also compare these RfQ, choose the best supplier for each product and create automatically the associated \
29 purchase orders.
30 ''',
31 'website': 'http://unifield.msf.org',
32 'init_xml': [
33 ],
34 'depends' : [
35 'purchase',
36 ],
37 'update_xml': [
38 'procurement_list_sequence.xml',
39 'procurement_list_view.xml',
40 'procurement_list_wizard.xml',
41 'wizard/wizard_import_list_view.xml',
42 'security/ir.model.access.csv',
43 ],
44 'demo_xml': [
45 ],
46 'test': [
47 'test/procurement_list.yml',
48 'test/procurement_copy.yml',
49 ],
50 'installable': True,
51 'active': False,
52}
53# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
054
=== added file 'procurement_list/procurement_list.py'
--- procurement_list/procurement_list.py 1970-01-01 00:00:00 +0000
+++ procurement_list/procurement_list.py 2011-03-16 16:41:25 +0000
@@ -0,0 +1,217 @@
1#!/usr/bin/env python
2# -*- encoding: utf-8 -*-
3##############################################################################
4#
5# OpenERP, Open Source Management Solution
6# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21##############################################################################
22
23import time
24import netsvc
25
26from osv import osv
27from osv import fields
28from tools.translate import _
29
30class procurement_list(osv.osv):
31 _name = 'procurement.list'
32 _description = 'Procurement list'
33
34 _columns = {
35 'name': fields.char(size=64, string='Ref.', required=True, readonly=True,
36 states={'draft': [('readonly', False)]}),
37 'requestor': fields.char(size=20, string='Requestor',),
38 'order_date': fields.date(string='Order date', required=True),
39 'warehouse_id': fields.many2one('stock.warehouse', string='Warehouse'),
40 'origin': fields.char(size=64, string='Origin'),
41 'state': fields.selection([('draft', 'Draft'),('done', 'Done'), ('cancel', 'Cancel')],
42 string='State', readonly=True),
43 'line_ids': fields.one2many('procurement.list.line', 'list_id', string='Lines', readonly=True,
44 states={'draft': [('readonly', False)]}),
45 'notes': fields.text(string='Notes'),
46 'supplier_ids': fields.many2many('res.partner', 'procurement_list_supplier_rel',
47 'list_id', 'supplier_id', string='Suppliers',
48 domain="[('supplier', '=', True)]",
49 states={'done': [('readonly', True)]}),
50 'order_ids': fields.many2many('purchase.order', 'procurement_list_order_rel',
51 'list_id', 'order_id', string='Orders', readonly=True),
52 }
53
54 _defaults = {
55 'name': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'procurement.list'),
56 'state': lambda *a: 'draft',
57 'order_date': lambda *a: time.strftime('%Y-%m-%d'),
58 }
59
60 def copy(self, cr, uid, ids, default={}, context={}):
61 '''
62 Increments the sequence for the new list
63 '''
64 default['name'] = self.pool.get('ir.sequence').get(cr, uid, 'procurement.list')
65
66 res = super(procurement_list, self).copy(cr, uid, ids, default, context=context)
67
68 return res
69
70 def cancel(self, cr, uid, ids, context={}):
71 '''
72 Sets the procurement list to the 'Cancel' state
73 '''
74 self.write(cr, uid, ids, {'state': 'cancel'})
75
76 return True
77
78 def create_rfq(self, cr, uid, ids, context={}):
79 '''
80 Create a RfQ per supplier with all products
81 '''
82 purchase_obj = self.pool.get('purchase.order')
83 line_obj = self.pool.get('purchase.order.line')
84
85 order_ids = []
86
87 for list in self.browse(cr, uid, ids, context=context):
88 # Returns an error message if no suppliers or no products
89 if not list.supplier_ids or len(list.supplier_ids) == 0:
90 raise osv.except_osv(_('Error'), _('No supplier defined for this list !'))
91 if not list.line_ids or len(list.line_ids) == 0:
92 raise osv.except_osv(_('Error'), _('No line defined for this list !'))
93
94 location_id = self._get_location(cr, uid, list.warehouse_id)
95 # Creates a RfQ for each supplier...
96 for supplier in list.supplier_ids:
97 po_id = purchase_obj.create(cr, uid, {'partner_id': supplier.id,
98 'partner_address_id': supplier.address_get().get('default'),
99 'pricelist_id': supplier.property_product_pricelist.id,
100 'origin': list.name,
101 'location_id': location_id})
102 order_ids.append(po_id)
103
104 # ... with all lines...
105 for line in list.line_ids:
106 # ... which aren't from stock
107 if not line.from_stock:
108 line_obj.create(cr, uid, {'product_uom': line.product_uom_id.id,
109 'product_id': line.product_id.id,
110 'order_id': po_id,
111 'price_unit': 0.00,
112 'date_planned': list.order_date,
113 'product_qty': line.product_qty,
114 'procurement_line_id': line.id,
115 'name': line.product_id.name,})
116 self.pool.get('procurement.list.line').write(cr, uid, line.id, {'latest': 'RfQ In Progress'})
117
118 self.write(cr, uid, ids, {'state': 'done', 'order_ids': [(6, 0, order_ids)]})
119
120 return {'type': 'ir.actions.act_window',
121 'res_model': 'purchase.order',
122 'view_type': 'form',
123 'view_mode': 'tree,form',
124 'domain': [('id', 'in', order_ids)]}
125
126 def reset(self, cr, uid, ids, context={}):
127 '''
128 Sets the procurement list to the 'Draft' state
129 '''
130 self.write(cr, uid, ids, {'state': 'draft'})
131
132 return True
133
134 def _get_location(self, cr, uid, warehouse=None):
135 '''
136 Returns the default input location for product
137 '''
138 if warehouse:
139 return warehouse.lot_input_id.id
140 warehouse_obj = self.pool.get('stock.warehouse')
141 warehouse_id = warehouse_obj.search(cr, uid, [])[0]
142 return warehouse_obj.browse(cr, uid, warehouse_id).lot_input_id.id
143
144procurement_list()
145
146
147class procurement_list_line(osv.osv):
148 _name = 'procurement.list.line'
149 _description = 'Procurement line'
150 _rec_name = 'product_id'
151
152 _columns = {
153 'product_id': fields.many2one('product.product', string='Product', required=True),
154 'product_uom_id': fields.many2one('product.uom', string='UoM', required=True),
155 'product_qty': fields.float(digits=(16,4), string='Quantity', required=True),
156 'comment': fields.char(size=128, string='Comment'),
157 'from_stock': fields.boolean(string='From stock ?'),
158 'latest': fields.char(size=64, string='Latest document', readonly=True),
159 'list_id': fields.many2one('procurement.list', string='List', required=True, ondelete='cascade'),
160 }
161
162 _defaults = {
163 'latest': lambda *a: '',
164 }
165
166 def copy_data(self, cr, uid, id, default={}, context={}):
167 '''
168 Initializes the 'latest' fields to an empty field
169 '''
170 default['latest'] = ''
171
172 res = super(procurement_list_line, self).copy_data(cr, uid, id, default, context=context)
173
174 return res
175
176 def product_id_change(self, cr, uid, ids, product_id, context={}):
177 '''
178 Fills automatically the product_uom_id field on the line when the
179 product was changed.
180 '''
181 product_obj = self.pool.get('product.product')
182
183 v = {}
184 if not product_id:
185 v.update({'product_uom_id': False})
186 else:
187 product = product_obj.browse(cr, uid, product_id, context=context)
188 v.update({'product_uom_id': product.uom_id.id})
189
190 return {'value': v}
191
192procurement_list_line()
193
194
195class purchase_order_line(osv.osv):
196 _name = 'purchase.order.line'
197 _inherit = 'purchase.order.line'
198
199 _columns = {
200 'procurement_line_id': fields.many2one('procurement.list.line', string='Procurement Line', readonly=True, ondelete='set null'),
201 }
202
203 def action_confirm(self, cr, uid, ids, context={}):
204 '''
205 Changes the status of the procurement line
206 '''
207 proc_line_obj = self.pool.get('procurement.list.line')
208 for line in self.browse(cr, uid, ids):
209 if line.procurement_line_id and line.procurement_line_id.id:
210 proc_line_obj.write(cr, uid, [line.procurement_line_id.id], {'latest': line.order_id.name})
211
212 return super(purchase_order_line, self).action_confirm(cr, uid, ids, context=context)
213
214purchase_order_line()
215
216# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
217
0218
=== added file 'procurement_list/procurement_list_sequence.xml'
--- procurement_list/procurement_list_sequence.xml 1970-01-01 00:00:00 +0000
+++ procurement_list/procurement_list_sequence.xml 2011-03-16 16:41:25 +0000
@@ -0,0 +1,20 @@
1<?xml version="1.0" encoding="utf-8" ?>
2<openerp>
3 <data>
4
5 <!-- Sequences for procurement.list -->
6 <record id="seq_type_procurement_list" model="ir.sequence.type">
7 <field name="name">Procurement List Order</field>
8 <field name="code">procurement.list</field>
9 </record>
10
11 <record id="seq_procurement_list" model="ir.sequence">
12 <field name="name">Procurement List</field>
13 <field name="code">procurement.list</field>
14 <field name="prefix">PR/</field>
15 <field name="padding">5</field>
16 </record>
17
18 </data>
19</openerp>
20
021
=== added file 'procurement_list/procurement_list_view.xml'
--- procurement_list/procurement_list_view.xml 1970-01-01 00:00:00 +0000
+++ procurement_list/procurement_list_view.xml 2011-03-16 16:41:25 +0000
@@ -0,0 +1,111 @@
1<?xml version="1.0" encoding="utf-8" ?>
2<openerp>
3 <data>
4
5 <record id="procurement_list_form_view" model="ir.ui.view">
6 <field name="name">procurement.list.form.view</field>
7 <field name="model">procurement.list</field>
8 <field name="type">form</field>
9 <field name="arch" type="xml">
10 <form string="Procurement list">
11 <group colspan="4" col="6">
12 <field name="name" />
13 <field name="order_date" />
14 <field name="warehouse_id" widget="selection" />
15 <field name="requestor" />
16 <field name="origin" />
17 </group>
18 <notebook colspan="4">
19 <page string="Products">
20 <field name="line_ids" mode="tree" colspan="4" nolabel="1">
21 <tree editable="top" string="Products">
22 <field name="product_id" on_change="product_id_change(product_id)" />
23 <field name="product_uom_id" />
24 <field name="product_qty" />
25 <field name="comment" />
26 <field name="from_stock" />
27 <field name="latest" />
28 </tree>
29 </field>
30 <group colspan="4" col="6">
31 <field name="state" />
32 <button name="cancel" string="Cancel" icon="gtk-cancel" type="object" states="draft"/>
33 <button name="create_rfq" string="Create RfQ" icon="gtk-execute" type="object" states="draft" />
34 <button name="reset" string="Reset to Draft" icon="gtk-ok" type="object" states="cancel" />
35 </group>
36 </page>
37 <page string="Suppliers">
38 <field name="supplier_ids" nolabel="1" />
39 </page>
40 <page string="Sourcing Documents">
41 <field name="order_ids" nolabel="1" colspan="4">
42 <tree string="Sourcing Documents" colors="blue:state=='draft'">
43 <field name="name" />
44 <field name="partner_id" />
45 <field name="state" />
46 </tree>
47 </field>
48 </page>
49 <page string="Notes">
50 <field name="notes" nolabel="1" />
51 </page>
52 </notebook>
53 </form>
54 </field>
55 </record>
56
57 <record id="procurement_list_tree_view" model="ir.ui.view">
58 <field name="name">procurement.list.tree.view</field>
59 <field name="model">procurement.list</field>
60 <field name="type">tree</field>
61 <field name="arch" type="xml">
62 <tree string="Procurement lists">
63 <field name="name" />
64 <field name="order_date" />
65 <field name="requestor" />
66 </tree>
67 </field>
68 </record>
69
70 <record id="procurement_list_filter_view" model="ir.ui.view">
71 <field name="name">procurement.list.filter.view</field>
72 <field name="model">procurement.list</field>
73 <field name="type">search</field>
74 <field name="arch" type="xml">
75 <search string="Search Procurement List">
76 <group col="10" colspan="4">
77 <filter icon="terp-document-new" string="Draft" domain="[('state', '=', 'draft')]" help="Draft Procurement list" />
78 <filter icon="terp-dialog-close" string="Done" domain="[('state', '=', 'done')]" help="Done Procurement list" />
79 <separator orientation="vertical" />
80 <field name="name" />
81 <field name="order_date" />
82 <field name="requestor" />
83 </group>
84 <newline />
85 <group expand="0" string="Group By..." colspan="4" col="10" groups="base.group_extended">
86 <filter string="Responsible" icon="terp-personal" domain="[]" context="{'group_by': 'user_id'}" />
87 <separator orientation="vertical" />
88 </group>
89 </search>
90 </field>
91 </record>
92
93 <record id="action_procurement_list_tree" model="ir.actions.act_window">
94 <field name="name">Procurement Lists</field>
95 <field name="res_model">procurement.list</field>
96 <field name="view_type">form</field>
97 <field name="view_mode">tree,form</field>
98 <field name="search_id" ref="procurement_list_filter_view" />
99 <field name="help">A procurement list is a list of items to supply. After creation of the list of items, you can choose
100 a list of suppliers and create automatically a Request for Quotation for each supplier.</field>
101 </record>
102
103 <menuitem
104 action="action_procurement_list_tree"
105 id="menu_procurement_list"
106 sequence="0"
107 parent="purchase.menu_procurement_management" />
108
109 </data>
110</openerp>
111
0112
=== added file 'procurement_list/procurement_list_wizard.xml'
--- procurement_list/procurement_list_wizard.xml 1970-01-01 00:00:00 +0000
+++ procurement_list/procurement_list_wizard.xml 2011-03-16 16:41:25 +0000
@@ -0,0 +1,21 @@
1<?xml version="1.0" encoding="utf-8" ?>
2<openerp>
3 <data>
4
5 <wizard
6 id="wizard_list_to_order"
7 model="procurement.list"
8 name="wizard_list_to_order"
9 keyword="client_action_relate"
10 string="Purchase Orders" />
11
12 <wizard
13 id="wizard_list_to_rfq"
14 model="procurement.list"
15 name="wizard_list_to_rfq"
16 keyword="client_action_relate"
17 string="Requests for Quotation" />
18
19 </data>
20</openerp>
21
022
=== added directory 'procurement_list/security'
=== added file 'procurement_list/security/ir.model.access.csv'
--- procurement_list/security/ir.model.access.csv 1970-01-01 00:00:00 +0000
+++ procurement_list/security/ir.model.access.csv 2011-03-16 16:41:25 +0000
@@ -0,0 +1,3 @@
1"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
2"access_procurement_list_all","procurement.list all","model_procurement_list",,1,1,1,1
3"access_procurement_list_line_all","procurement.list.line all","model_procurement_list_line",,1,1,1,1
04
=== added directory 'procurement_list/test'
=== added file 'procurement_list/test/list_import.csv'
--- procurement_list/test/list_import.csv 1970-01-01 00:00:00 +0000
+++ procurement_list/test/list_import.csv 2011-03-16 16:41:25 +0000
@@ -0,0 +1,5 @@
1'CPU1';'Processor AMD Athlon XP 1800+';'PCE';12,00;'test import';
2'CPU2';'High speed processor config';'PCE';15,00;;'True'
3'CPU3';'Processor AMD Athlon XP 2200+';'PCE';25,00;;
4'CPU_DEM';'Processor on demand';'PCE';30,00;;
5'CPU_GEN';'Regular processor config';'PCE';32,00;;
06
=== added file 'procurement_list/test/procurement_list.yml'
--- procurement_list/test/procurement_list.yml 1970-01-01 00:00:00 +0000
+++ procurement_list/test/procurement_list.yml 2011-03-16 16:41:25 +0000
@@ -0,0 +1,143 @@
1-
2 In order to test the procurement list module, I start by creating a new product category
3-
4 !record {model: product.category, id: product_cat1}:
5 name: Categ1
6-
7 I create new product 'P1'
8-
9 !record {model: product.product, id: product1}:
10 categ_id: product_cat1
11 cost_method: standard
12 mes_type: fixed
13 name: P1
14 price_margin: 2.0
15 procure_method: make_to_stock
16 property_stock_inventory: stock.location_inventory
17 property_stock_procurement: stock.location_procurement
18 property_stock_production: stock.location_production
19 seller_delay: '1'
20 standard_price: 100.0
21 supply_method: buy
22 type: product
23 uom_id: product.product_uom_unit
24 uom_po_id: product.product_uom_unit
25 volume: 0.0
26 warranty: 0.0
27 weight: 0.0
28 weight_net: 0.0
29-
30 I create a second product, P2
31-
32 !record {model: product.product, id: product2}:
33 categ_id: product_cat1
34 cost_method: standard
35 mes_type: fixed
36 name: P2
37 price_margin: 2.0
38 procure_method: make_to_stock
39 property_stock_inventory: stock.location_inventory
40 property_stock_procurement: stock.location_procurement
41 property_stock_production: stock.location_production
42 seller_delay: '1'
43 standard_price: 100.0
44 supply_method: buy
45 type: product
46 uom_id: product.product_uom_unit
47 uom_po_id: product.product_uom_unit
48 volume: 0.0
49 warranty: 0.0
50 weight: 0.0
51 weight_net: 0.0
52-
53 I create a partner
54-
55 !record {model: res.partner, id: partner1}:
56 name: Supplier 1
57-
58 I create an address for this partner
59-
60 !record {model: res.partner.address, id: addr1}:
61 partner_id: partner1
62 name: Supplier1
63-
64 I create a second partner
65-
66 !record {model: res.partner, id: partner2}:
67 name: Supplier 2
68-
69 I create an address for this second partner
70-
71 !record {model: res.partner.address, id: addr2}:
72 partner_id: partner2
73 name: Supplier2
74-
75 I create a procurement list for these two products
76-
77 !record {model: procurement.list, id: list1}:
78 requestor: Administration
79 warehouse_id: stock.warehouse0
80 origin: R 20043
81 supplier_ids:
82 - partner1
83 - partner2
84-
85 I add two lines in this procurement list
86-
87 !record {model: procurement.list.line, id: list1_line1}:
88 product_id: product1
89 product_uom_id: product.product_uom_unit
90 product_qty: 100.00
91 comment: special comment
92 from_stock: False
93 list_id: list1
94-
95 The second line
96-
97 !record {model: procurement.list.line, id: list1_line2}:
98 product_id: product2
99 product_uom_id: product.product_uom_unit
100 product_qty: 50.0
101 from_stock: True
102 list_id: list1
103-
104 I check that the list which was initially in the draft state
105-
106 !assert {model: procurement.list, id: list1}:
107 - state == 'draft'
108 - requestor == 'Administration'
109 - origin == 'R 20043'
110-
111 I create RfQ from this list
112-
113 !python {model: procurement.list}: |
114 pl_obj = self.pool.get('procurement.list')
115 pl_id1 = pl_obj.browse(cr, uid, ref('list1'))
116 pl_id1.create_rfq()
117-
118 I check if the latest message in procurement line is 'RfQ In Progress'
119-
120 !assert {model: procurement.list.line, id: list1_line1}:
121 - latest == 'RfQ In Progress'
122-
123 I check if only one RfQ will be created for the
124-
125 !python {model: procurement.list}: |
126 pl_obj = self.pool.get('procurement.list')
127 pol_obj = self.pool.get('purchase.order.line')
128 order_obj = self.pool.get('purchase.order')
129 pol_ids = pol_obj.search(cr, uid, [('product_id', '=', ref('product1'))])
130 pl = pl_obj.browse(cr, uid, ref('list1'))
131
132 for pol in pol_obj.browse(cr, uid, pol_ids):
133 assert pol.order_id.origin == pl.name, "Bad name for the name of the generated Purchase Order"
134 order_obj.wkf_confirm_order(cr, uid, [pol.order_id.id])
135 assert pol.procurement_line_id.latest == pol.order_id.name, "Procurement line not updated"
136-
137 I check that no purchase order line with P2
138-
139 !python {model: procurement.list}: |
140 pl_obj = self.pool.get('procurement.list')
141 pol_obj = self.pool.get('purchase.order.line')
142 pol_ids = pol_obj.search(cr, uid, [('product_id', '=', ref('product2'))])
143 assert len(pol_ids) == 0, "No purchase order line found !"
0144
=== added directory 'procurement_list/wizard'
=== added file 'procurement_list/wizard/__init__.py'
--- procurement_list/wizard/__init__.py 1970-01-01 00:00:00 +0000
+++ procurement_list/wizard/__init__.py 2011-03-16 16:41:25 +0000
@@ -0,0 +1,28 @@
1#!/usr/bin/env python
2# -*- encoding: utf-8 -*-
3##############################################################################
4#
5# OpenERP, Open Source Management Solution
6# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21##############################################################################
22
23import wizard_list_to_order
24import wizard_list_to_rfq
25import wizard_import_list
26
27# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
28
029
=== added file 'procurement_list/wizard/wizard_import_list.py'
--- procurement_list/wizard/wizard_import_list.py 1970-01-01 00:00:00 +0000
+++ procurement_list/wizard/wizard_import_list.py 2011-03-16 16:41:25 +0000
@@ -0,0 +1,196 @@
1#!/usr/bin/env python
2# -*- encoding: utf-8 -*-
3##############################################################################
4#
5# OpenERP, Open Source Management Solution
6# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21##############################################################################
22
23from osv import osv
24from osv import fields
25
26from tools.translate import _
27
28from tempfile import TemporaryFile
29
30import base64
31import csv
32
33
34
35class wizard_import_list(osv.osv_memory):
36 _name = 'procurement.list.import'
37 _description = 'Import of Procurement List'
38
39 _columns = {
40 'file': fields.binary(strign='File to import', required=True),
41 'message': fields.text(string='Message', readonly=True),
42 'info': fields.text(string='Info', readonly=True),
43 }
44
45 _defaults = {
46 'info': lambda *a : """
47 The file should be in CSV format (with ';' character as delimiter).
48 The columns should be in this order :
49 * Product code
50 * Product name
51 * UoM
52 * Quantity
53 * Comment
54 * From stock ? (Write True if you want that the product will be supply from stock, leave blank if not)
55 """
56 }
57
58 def close_window(self, cr, uid, ids, context={}):
59 '''
60 Simply close the wizard
61 '''
62 return {'type': 'ir.actions.act_window',
63 'res_model': 'procurement.list',
64 'view_type': 'form',
65 'view_mode': 'form,tree',
66 'res_id': context.get('list_id'),
67 'target': 'crush'}
68
69 def default_get(self, cr, uid, fields, context={}):
70 '''
71 Check if the Procurement List is saved and
72 set the error message
73 '''
74 res = super(wizard_import_list, self).default_get(cr, uid, fields, context=context)
75
76 # If we are after the importation
77 if context.get('step', False) and context.get('step', False) == 'import':
78 res['message'] = context.get('message', '')
79
80 return res
81 else:
82 if not context.get('active_id', False):
83 raise osv.except_osv(_('Warning'), _('Please save the Procurement List before importing lines'))
84
85 # We check if the Procurement List is in 'Draft' state
86 list_id = self.pool.get('procurement.list').browse(cr, uid, context.get('active_id', []))
87 if not list_id or list_id.state != 'draft':
88 raise osv.except_osv(_('Warning'), _('You cannot import lines in a confirmed Procurement List'))
89
90 return res
91
92
93 def import_file(self, cr, uid, ids, context={}):
94 '''
95 Import the file passed on the wizard in the
96 Procurement List
97 '''
98 list_line_obj = self.pool.get('procurement.list.line')
99 list_obj = self.pool.get('procurement.list')
100 product_obj = self.pool.get('product.product')
101 uom_obj = self.pool.get('product.uom')
102 model_data_obj = self.pool.get('ir.model.data')
103
104 list_id = context.get('active_id', False)
105
106 if not list_id:
107 raise osv.except_osv(_('Error'), _('The system hasn\'t found a Procurement List to import lines'))
108
109 import_list = self.browse(cr, uid, ids[0], context)
110
111 fileobj = TemporaryFile('w+')
112 fileobj.write(base64.decodestring(import_list.file))
113
114 # now we determine the file format
115 fileobj.seek(0)
116
117 reader = csv.reader(fileobj, quotechar='\'', delimiter=';')
118
119 error = ''
120
121 line_num = 0
122
123 for line in reader:
124 line_num += 1
125 if len(line) < 6:
126 error += 'Line %s is not valid !' % (line_num)
127 error += '\n'
128 continue
129 # Get the product
130 product_ids = product_obj.search(cr, uid, [('default_code', '=', line[0])], context=context)
131 if not product_ids:
132 product_ids = product_obj.search(cr, uid, [('name', '=', line[1])], context=context)
133
134 if not product_ids:
135 error += 'Product [%s] %s not found !' % (line[0], line[1])
136 error += '\n'
137 continue
138
139 product_id = product_ids[0]
140
141 # Get the UoM
142 uom_ids = uom_obj.search(cr, uid, [('name', '=', line[2])])
143 if not uom_ids:
144 error += 'Uom %s not found !' % line[2]
145 error += '\n'
146 continue
147
148 uom_id = uom_ids[0]
149
150 # Get the quantity
151 product_qty = float(line[3].replace(',', '.'))
152
153 # Get the comment
154 comment = line[4]
155
156 # Get the method
157 from_stock = False
158 if line[5] == 'True':
159 from_stock = True
160
161
162 list_line_obj.create(cr, uid, {'product_id': product_id,
163 'product_uom_id': uom_id,
164 'product_qty': product_qty,
165 'comment': comment,
166 'from_stock': from_stock,
167 'list_id': list_id})
168
169 view_ids = model_data_obj.search(cr, uid,
170 [('module', '=', 'procurement_list'),
171 ('name', '=', 'wizard_import_list_done')],
172 offset=0, limit=1)[0]
173 view_id = model_data_obj.browse(cr, uid, view_ids).res_id
174
175 if error and error != '':
176 context['message'] = error
177 else:
178 context['message'] = 'All lines have been succesfully imported !'
179
180 context['step'] = 'import'
181 context['list_id'] = list_id
182
183 return {'type': 'ir.actions.act_window',
184 'res_model': 'procurement.list.import',
185 'view_type': 'form',
186 'view_mode': 'form',
187 'target': 'new',
188 'view_id': [view_id],
189 'context': context,
190 }
191
192wizard_import_list()
193
194
195# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
196
0197
=== added file 'procurement_list/wizard/wizard_import_list_view.xml'
--- procurement_list/wizard/wizard_import_list_view.xml 1970-01-01 00:00:00 +0000
+++ procurement_list/wizard/wizard_import_list_view.xml 2011-03-16 16:41:25 +0000
@@ -0,0 +1,48 @@
1<?xml version="1.0" encoding="utf-8" ?>
2<openerp>
3 <data>
4
5
6 <record id="wizard_import_list_init" model="ir.ui.view">
7 <field name="name">wizard.import.list.init</field>
8 <field name="model">procurement.list.import</field>
9 <field name="type">form</field>
10 <field name="arch" type="xml">
11 <form string="Import lines">
12 <separator string="Information" colspan="4" />
13 <field name="info" colspan="4" nolabel="1" />
14 <separator string="File to import" colspan="4" />
15 <field name="file" nolabel="1" colspan="4" />
16 <button special="cancel" string="Cancel" icon="gtk-cancel" />
17 <button name="import_file" string="Import file" type="object" icon="gtk-convert" />
18 </form>
19 </field>
20 </record>
21
22 <record id="wizard_import_list_done" model="ir.ui.view">
23 <field name="name">wizard.import.list.done</field>
24 <field name="model">procurement.list.import</field>
25 <field name="type">form</field>
26 <field name="arch" type="xml">
27 <form string="Result of importation">
28 <separator colspan="4" string="Result of importation" />
29 <field name="message" colspan="4" nolabel="1" />
30 <button name="close_window" string="Close" icon="gtk-close" type="object" />
31 </form>
32 </field>
33 </record>
34
35 <act_window
36 name="Import lines"
37 res_model="procurement.list.import"
38 src_model="procurement.list"
39 view_mode="form"
40 view_type="form"
41 view_id="wizard_import_list_init"
42 target="new"
43 key2="client_action_multi"
44 id="action_open_wizard_import" />
45
46 </data>
47</openerp>
48
049
=== added file 'procurement_list/wizard/wizard_list_to_order.py'
--- procurement_list/wizard/wizard_list_to_order.py 1970-01-01 00:00:00 +0000
+++ procurement_list/wizard/wizard_list_to_order.py 2011-03-16 16:41:25 +0000
@@ -0,0 +1,63 @@
1#!/usr/bin/env python
2# -*- encoding: utf-8 -*-
3##############################################################################
4#
5# OpenERP, Open Source Management Solution
6# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21##############################################################################
22
23import wizard
24import pooler
25
26class wizard_list_to_order(wizard.interface):
27
28 def _get_order(self, cr, uid, data, context={}):
29 '''
30 Returns the Purchase Orders generated by the current
31 Procurement List
32 '''
33 pool_obj = pooler.get_pool(cr.dbname)
34 list_obj = pool_obj.get('procurement.list')
35
36 order_ids = []
37
38 for l in list_obj.browse(cr, uid, data['ids'], context=context):
39 for o in l.order_ids:
40 order_ids.append(o.id)
41
42 return {'type': 'ir.actions.act_window',
43 'res_model': 'purchase.order',
44 'view_type': 'form',
45 'view_mode': 'tree,form',
46 'domain': [('state', '!=', 'draft'), ('id', 'in', order_ids)],
47 }
48
49 states = {
50 'init': {
51 'actions': [],
52 'result': {
53 'type': 'action',
54 'action': _get_order,
55 'state': 'end',
56 },
57 },
58 }
59
60wizard_list_to_order('wizard_list_to_order')
61
62# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
63
064
=== added file 'procurement_list/wizard/wizard_list_to_rfq.py'
--- procurement_list/wizard/wizard_list_to_rfq.py 1970-01-01 00:00:00 +0000
+++ procurement_list/wizard/wizard_list_to_rfq.py 2011-03-16 16:41:25 +0000
@@ -0,0 +1,63 @@
1#!/usr/bin/env python
2# -*- encoding: utf-8 -*-
3##############################################################################
4#
5# OpenERP, Open Source Management Solution
6# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21##############################################################################
22
23import wizard
24import pooler
25
26class wizard_list_to_rfq(wizard.interface):
27
28 def _get_order(self, cr, uid, data, context={}):
29 '''
30 Returns the Requests for Quotation generated by the current
31 Procurement List
32 '''
33 pool_obj = pooler.get_pool(cr.dbname)
34 list_obj = pool_obj.get('procurement.list')
35
36 order_ids = []
37
38 for l in list_obj.browse(cr, uid, data['ids'], context=context):
39 for o in l.order_ids:
40 order_ids.append(o.id)
41
42 return {'type': 'ir.actions.act_window',
43 'res_model': 'purchase.order',
44 'view_type': 'form',
45 'view_mode': 'tree,form',
46 'domain': [('state', '=', 'draft'), ('id', 'in', order_ids)],
47 }
48
49 states = {
50 'init': {
51 'actions': [],
52 'result': {
53 'type': 'action',
54 'action': _get_order,
55 'state': 'end',
56 },
57 },
58 }
59
60wizard_list_to_rfq('wizard_list_to_rfq')
61
62# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
63

Subscribers

People subscribed via source and target branches

to all changes: