forked from OCA/field-service
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfsm_order.py
234 lines (209 loc) · 9.67 KB
/
fsm_order.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# Copyright (C) 2018 - TODAY, Brian McMaster
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from datetime import datetime, timedelta
from odoo import api, fields, models, _
from odoo.tools import (DEFAULT_SERVER_DATETIME_FORMAT,
float_is_zero, float_compare)
from odoo.addons import decimal_precision as dp
from odoo.exceptions import UserError
from odoo.addons.base_geoengine import geo_model
class FSMOrder(geo_model.GeoModel):
_inherit = 'fsm.order'
line_ids = fields.One2many(
'fsm.order.line', 'order_id', string="Order Lines",)
picking_ids = fields.One2many('stock.picking', 'fsm_order_id',
string='Transfers')
delivery_count = fields.Integer(string='Delivery Orders',
compute='_compute_picking_ids')
procurement_group_id = fields.Many2one(
'procurement.group', 'Procurement Group', copy=False)
warehouse_id = fields.Many2one('stock.warehouse', string='Warehouse',
help="Warehouse used to ship the materials")
@api.depends('picking_ids')
def _compute_picking_ids(self):
for order in self:
order.delivery_count = len(order.picking_ids)
def action_confirm(self):
if self.location_id and self.line_ids and self.warehouse_id:
self.line_ids._confirm_picking()
return super(FSMOrder, self).action_confirm()
else:
raise UserError(_('Please select the location, a warehouse and a'
' product.'))
@api.multi
def action_view_delivery(self):
'''
This function returns an action that display existing delivery orders
of given fsm order ids. It can either be a in a list or in a form
view, if there is only one delivery order to show.
'''
action = self.env.ref('stock.action_picking_tree_all').read()[0]
pickings = self.mapped('picking_ids')
if len(pickings) > 1:
action['domain'] = [('id', 'in', pickings.ids)]
elif pickings:
action['views'] = [(self.env.ref('stock.view_picking_form').id, 'form')]
action['res_id'] = pickings.id
return action
class FSMOrderLine(models.Model):
_name = 'fsm.order.line'
_description = "FSM Order Lines"
_order = 'order_id, sequence, id'
order_id = fields.Many2one(
'fsm.order', string="FSM Order", required=True,
ondelete='cascade', index=True, copy=False,
readonly=True, states={'draft': [('readonly', False)]})
name = fields.Char(string='Description', required=True,
readonly=True, states={'draft': [('readonly', False)]})
sequence = fields.Integer(string='Sequence', default=10, readonly=True,
states={'draft': [('readonly', False)]})
product_id = fields.Many2one(
'product.product', string="Product",
domain=[('type', '=', 'product')], ondelete='restrict',
readonly=True, states={'draft': [('readonly', False)]})
product_uom_id = fields.Many2one(
'product.uom', string='Unit of Measure', required=True,
readonly=True, states={'draft': [('readonly', False)]})
qty_ordered = fields.Float(
string='Quantity Requested', readonly=True,
states={'draft': [('readonly', False)]},
digits=dp.get_precision('Product Unit of Measure'))
qty_delivered = fields.Float(
string='Quantity Delivered', readonly=True, copy=False,
digits=dp.get_precision('Product Unit of Measure'))
state = fields.Selection([
('draft', 'Draft'),
('confirmed', 'Confirmed'),
('partial', 'Partially Shipped'),
('done', 'Done')],
string='State', compute='_compute_state', copy=False, index=True,
readonly=True, store=True)
move_ids = fields.One2many(
'stock.move', 'fsm_order_line_id', string='Stock Moves',
readonly=True, states={'draft': [('readonly', False)]})
@api.depends('move_ids', 'qty_ordered', 'qty_delivered')
def _compute_state(self):
precision = self.env['decimal.precision'].precision_get(
'Product Unit of Measure')
for line in self:
if line.move_ids and not float_is_zero(line.qty_delivered,
precision_digits=precision):
if float_compare(line.qty_delivered, line.qty_ordered,
precision_digits=precision) == -1:
line.state = 'partial'
elif float_compare(line.qty_delivered, line.qty_ordered,
precision_digits=precision) >= 0:
line.state = 'done'
elif line.move_ids:
line.state = 'confirmed'
else:
line.state = 'draft'
@api.multi
@api.onchange('product_id')
def onchange_product_id(self):
if not self.product_id:
return {'domain': {'product_uom': []}}
vals = {}
domain = {'product_uom': [('category_id', '=',
self.product_id.uom_id.category_id.id)]}
if (not self.product_uom_id
or (self.product_id.uom_id.id != self.product_uom_id.id)):
vals['product_uom_id'] = self.product_id.uom_id
vals['qty_ordered'] = 1.0
product = self.product_id.with_context(
quantity=vals.get('qty_ordered') or self.qty_ordered,
uom=self.product_uom_id.id,
)
result = {'domain': domain}
name = product.name_get()[0][1]
if product.description_sale:
name += '\n' + product.description_sale
vals['name'] = name
self.update(vals)
return result
@api.multi
def _prepare_procurement_values(self, group_id=False):
self.ensure_one()
values = {}
date_planned = (self.order_id.scheduled_date_start
or self.order_id.request_early
or self.order_id.request_late
or (datetime.now() + timedelta(days=1)).strftime(
DEFAULT_SERVER_DATETIME_FORMAT))
values.update({
'group_id': group_id,
'fsm_order_line_id': self.id,
'date_planned': date_planned,
'route_ids': self.order_id.warehouse_id.delivery_route_id,
'partner_dest_id': self.order_id.customer_id
})
return values
def _get_procurement_qty(self):
self.ensure_one()
qty = 0.0
for move in self.move_ids.filtered(lambda r: r.state != 'cancel'):
if move.picking_code == 'outgoing':
qty += move.product_uom._compute_quantity(
move.product_uom_qty, self.product_uom_id,
rounding_method='HALF-UP')
elif move.picking_code == 'incoming':
qty -= move.product_uom._compute_quantity(
move.product_uom_qty, self.product_uom_id,
rounding_method='HALF-UP')
return qty
@api.multi
def _confirm_picking(self):
precision = self.env['decimal.precision'].precision_get(
'Product Unit of Measure')
errors = []
for line in self:
qty_procured = line._get_procurement_qty()
if float_compare(qty_procured, line.qty_ordered,
precision_digits=precision) >= 0:
continue
group_id = line.order_id.procurement_group_id
if not group_id:
group_id = self.env['procurement.group'].create({
'name': line.order_id.name,
'move_type': 'direct',
'fsm_order_id': line.order_id.id,
'partner_id': line.order_id.customer_id.id,
})
line.order_id.procurement_group_id = group_id
values = line._prepare_procurement_values(group_id=group_id)
qty_needed = line.qty_ordered - qty_procured
procurement_uom = line.product_uom_id
quant_uom = line.product_id.uom_id
get_param = self.env['ir.config_parameter'].sudo().get_param
import pdb;pdb.set_trace()
if (procurement_uom.id != quant_uom.id
and get_param('stock.propagate_uom') != '1'):
qty_needed = line.product_uom_id._compute_quantity(
qty_needed, quant_uom, rounding_method='HALF-UP')
procurement_uom = quant_uom
try:
self.env['procurement.group'].run(
line.product_id, qty_needed, procurement_uom,
line.order_id.location_id.inventory_location,
line.name, line.order_id.name, values)
except UserError as error:
errors.append(error.name)
if errors:
raise UserError('\n'.join(errors))
return True
@api.multi
def _get_delivered_qty(self):
self.ensure_one()
qty = 0.0
for move in self.move_ids.filtered(lambda r: r.state == 'done'
and not r.scrapped):
if move.location_dest_id.usage == "customer":
if (not move.origin_returned_move_id
or (move.origin_returned_move_id and move.to_refund)):
qty += move.product_uom._compute_quantity(
move.product_uom_qty, self.product_uom_id)
elif (move.location_dest_id.usage != "customer"
and move.to_refund):
qty -= move.product_uom._compute_quantity(
move.product_uom_qty, self.product_uom_id)
return qty