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
|
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api,fields, models
from odoo.exceptions import UserError, ValidationError
from odoo.tools import float_is_zero, float_compare
from itertools import groupby
class StockPicking(models.Model):
_inherit='stock.picking'
pos_session_id = fields.Many2one('pos.session')
pos_order_id = fields.Many2one('pos.order')
def _prepare_picking_vals(self, partner, picking_type, location_id, location_dest_id):
return {
'partner_id': partner.id if partner else False,
'user_id': False,
'picking_type_id': picking_type.id,
'move_type': 'direct',
'location_id': location_id,
'location_dest_id': location_dest_id,
}
@api.model
def _create_picking_from_pos_order_lines(self, location_dest_id, lines, picking_type, partner=False):
"""We'll create some picking based on order_lines"""
pickings = self.env['stock.picking']
stockable_lines = lines.filtered(lambda l: l.product_id.type in ['product', 'consu'] and not float_is_zero(l.qty, precision_rounding=l.product_id.uom_id.rounding))
if not stockable_lines:
return pickings
positive_lines = stockable_lines.filtered(lambda l: l.qty > 0)
negative_lines = stockable_lines - positive_lines
if positive_lines:
location_id = picking_type.default_location_src_id.id
positive_picking = self.env['stock.picking'].create(
self._prepare_picking_vals(partner, picking_type, location_id, location_dest_id)
)
positive_picking._create_move_from_pos_order_lines(positive_lines)
try:
with self.env.cr.savepoint():
positive_picking._action_done()
except (UserError, ValidationError):
pass
pickings |= positive_picking
if negative_lines:
if picking_type.return_picking_type_id:
return_picking_type = picking_type.return_picking_type_id
return_location_id = return_picking_type.default_location_dest_id.id
else:
return_picking_type = picking_type
return_location_id = picking_type.default_location_src_id.id
negative_picking = self.env['stock.picking'].create(
self._prepare_picking_vals(partner, return_picking_type, location_dest_id, return_location_id)
)
negative_picking._create_move_from_pos_order_lines(negative_lines)
try:
with self.env.cr.savepoint():
negative_picking._action_done()
except (UserError, ValidationError):
pass
pickings |= negative_picking
return pickings
def _prepare_stock_move_vals(self, first_line, order_lines):
return {
'name': first_line.name,
'product_uom': first_line.product_id.uom_id.id,
'picking_id': self.id,
'picking_type_id': self.picking_type_id.id,
'product_id': first_line.product_id.id,
'product_uom_qty': abs(sum(order_lines.mapped('qty'))),
'state': 'draft',
'location_id': self.location_id.id,
'location_dest_id': self.location_dest_id.id,
'company_id': self.company_id.id,
}
def _create_move_from_pos_order_lines(self, lines):
self.ensure_one()
lines_by_product = groupby(sorted(lines, key=lambda l: l.product_id.id), key=lambda l: l.product_id.id)
for product, lines in lines_by_product:
order_lines = self.env['pos.order.line'].concat(*lines)
first_line = order_lines[0]
current_move = self.env['stock.move'].create(
self._prepare_stock_move_vals(first_line, order_lines)
)
confirmed_moves = current_move._action_confirm()
for move in confirmed_moves:
if first_line.product_id == move.product_id and first_line.product_id.tracking != 'none':
if self.picking_type_id.use_existing_lots or self.picking_type_id.use_create_lots:
for line in order_lines:
sum_of_lots = 0
for lot in line.pack_lot_ids.filtered(lambda l: l.lot_name):
if line.product_id.tracking == 'serial':
qty = 1
else:
qty = abs(line.qty)
ml_vals = move._prepare_move_line_vals()
ml_vals.update({'qty_done':qty})
if self.picking_type_id.use_existing_lots:
existing_lot = self.env['stock.production.lot'].search([
('company_id', '=', self.company_id.id),
('product_id', '=', line.product_id.id),
('name', '=', lot.lot_name)
])
if not existing_lot and self.picking_type_id.use_create_lots:
existing_lot = self.env['stock.production.lot'].create({
'company_id': self.company_id.id,
'product_id': line.product_id.id,
'name': lot.lot_name,
})
quant = existing_lot.quant_ids.filtered(lambda q: q.quantity > 0.0 and q.location_id.parent_path.startswith(move.location_id.parent_path))[-1:]
ml_vals.update({
'lot_id': existing_lot.id,
'location_id': quant.location_id.id or move.location_id.id
})
else:
ml_vals.update({
'lot_name': lot.lot_name,
})
self.env['stock.move.line'].create(ml_vals)
sum_of_lots += qty
if abs(line.qty) != sum_of_lots:
difference_qty = abs(line.qty) - sum_of_lots
ml_vals = current_move._prepare_move_line_vals()
if line.product_id.tracking == 'serial':
ml_vals.update({'qty_done': 1})
for i in range(int(difference_qty)):
self.env['stock.move.line'].create(ml_vals)
else:
ml_vals.update({'qty_done': difference_qty})
self.env['stock.move.line'].create(ml_vals)
else:
move._action_assign()
for move_line in move.move_line_ids:
move_line.qty_done = move_line.product_uom_qty
if float_compare(move.product_uom_qty, move.quantity_done, precision_rounding=move.product_uom.rounding) > 0:
remaining_qty = move.product_uom_qty - move.quantity_done
ml_vals = move._prepare_move_line_vals()
ml_vals.update({'qty_done':remaining_qty})
self.env['stock.move.line'].create(ml_vals)
else:
move._action_assign()
for move_line in move.move_line_ids:
move_line.qty_done = move_line.product_uom_qty
if float_compare(move.product_uom_qty, move.quantity_done, precision_rounding=move.product_uom.rounding) > 0:
remaining_qty = move.product_uom_qty - move.quantity_done
ml_vals = move._prepare_move_line_vals()
ml_vals.update({'qty_done':remaining_qty})
self.env['stock.move.line'].create(ml_vals)
move.quantity_done = move.product_uom_qty
def _send_confirmation_email(self):
# Avoid sending Mail/SMS for POS deliveries
pickings = self.filtered(lambda p: p.picking_type_id != p.picking_type_id.warehouse_id.pos_type_id)
return super(StockPicking, pickings)._send_confirmation_email()
|