Bug create contract

This commit is contained in:
2026-05-14 16:40:23 +02:00
parent dd2b6952bc
commit 4925cc8bfd
3 changed files with 354 additions and 241 deletions

View File

@@ -749,7 +749,11 @@ class BotWizard(Wizard):
lms.lot_r_id = ls.getLotQt()[0].id
lms.lot_matched_qt = lp.lot_quantity
lms.lot_sale = s
LotQt.match_lots([lmp],[lms])
Lot = Pool().get('lot.lot')
with Lot.skip_quantity_consistency():
LotQt.match_lots([lmp],[lms])
Lot.assert_lines_quantity_consistency(
[p.lines[0], s.lines[0]])
Sale._process_shipment([s])
elif do_ == "add":
@@ -876,4 +880,4 @@ class BotAction(ModelSQL, ModelView):
@classmethod
def state_dashboard(cls):
return 1
return 1

View File

@@ -230,6 +230,11 @@ class Lot(metaclass=PoolMeta):
if getattr(lot, 'sale_line', None):
lines.append(lot.sale_line)
cls.assert_lines_quantity_consistency(lines)
@staticmethod
def skip_quantity_consistency():
return Transaction().set_context(
_purchase_trade_skip_quantity_consistency=True)
line = fields.Many2One('purchase.line',"Purchase",ondelete='CASCADE')
move = fields.Function(fields.Many2One('stock.move',"Move"),'get_current_move')
@@ -1308,8 +1313,7 @@ class LotQt(
lqt.lot_p.line.unit)))
tot_qt = round(tot_qt, 5)
cls._warn_physical_lot_tolerance(lqt, vlots)
with Transaction().set_context(
_purchase_trade_skip_quantity_consistency=True):
with Lot.skip_quantity_consistency():
# Consume the forecast first. Physical lot saves recompute the
# virtual lot, so the matching lot.qt must already carry the
# target open quantity during the rest of the transaction.
@@ -2656,72 +2660,73 @@ class LotShipping(Wizard):
affected_lines = []
if not self.ship.shipment:
pass
for r in self.records:
if r.r_lot_shipment_in:
raise UserError("Please unlink before linking to a new shipment !")
else:
shipped_quantity = Decimal(str(r.r_lot_quantity)).quantize(Decimal("0.00001"))
logger.info("LotShipping:%s",shipped_quantity)
shipment_origin = None
if self.ship.quantity:
shipped_quantity = self.ship.quantity
if shipped_quantity == 0:
shipped_quantity = Decimal(str(r.r_lot_matched)).quantize(Decimal("0.00001"))
if self.ship.shipment == 'in':
if not self.ship.shipment_in:
UserError("Shipment not known!")
shipment_origin = 'stock.shipment.in,'+str(self.ship.shipment_in.id)
elif self.ship.shipment == 'out':
if not self.ship.shipment_out:
UserError("Shipment not known!")
shipment_origin = 'stock.shipment.out,'+str(self.ship.shipment_out.id)
elif self.ship.shipment == 'int':
if not self.ship.shipment_internal:
UserError("Shipment not known!")
shipment_origin = 'stock.shipment.internal,'+str(self.ship.shipment_internal.id)
if r.id < 10000000 :
l = Lot(r.id)
logger.info("IN_SHIPPING1:%s",l)
if self.ship.shipment == 'in':
l.lot_shipment_in = self.ship.shipment_in
elif self.ship.shipment == 'out':
l.lot_shipment_out = self.ship.shipment_out
elif self.ship.shipment == 'int':
l.lot_shipment_internal = self.ship.shipment_internal
logger.info("IN_SHIPPING2:%s",l.move)
if not l.move:
continue
logger.info("IN_SHIPPING3:%s",r)
move = Move(l.move)
move.shipment = shipment_origin
Move.save([move])
linked_transit_move = move.get_linked_transit_move()
if linked_transit_move:
linked_transit_move.shipment = shipment_origin
Move.save([linked_transit_move])
#Decrease forecasted virtual part shipped
vlot_p = l.getVlot_p()
l.updateVirtualPart(-l.get_current_quantity_converted(),shipment_origin,l.getVlot_s())
l.lot_av = 'reserved'
Lot.save([l])
l.set_current_quantity(l.lot_quantity,l.lot_gross_quantity,2)
Lot.save([l])
if l.line:
affected_lines.append(l.line)
if l.sale_line:
affected_lines.append(l.sale_line)
with Lot.skip_quantity_consistency():
for r in self.records:
if r.r_lot_shipment_in:
raise UserError("Please unlink before linking to a new shipment !")
else:
lqt = LotQt(r.id - 10000000)
#Increase forecasted virtual part shipped
if not lqt.lot_p.updateVirtualPart(shipped_quantity,shipment_origin,lqt.lot_s):
logger.info("LotShipping2:%s",shipped_quantity)
lqt.lot_p.createVirtualPart(shipped_quantity,shipment_origin,lqt.lot_s)
#Decrease forecasted virtual part non shipped
lqt.lot_p.updateVirtualPart(-shipped_quantity,None,lqt.lot_s)
if lqt.lot_p and lqt.lot_p.line:
affected_lines.append(lqt.lot_p.line)
if lqt.lot_s and lqt.lot_s.sale_line:
affected_lines.append(lqt.lot_s.sale_line)
shipped_quantity = Decimal(str(r.r_lot_quantity)).quantize(Decimal("0.00001"))
logger.info("LotShipping:%s",shipped_quantity)
shipment_origin = None
if self.ship.quantity:
shipped_quantity = self.ship.quantity
if shipped_quantity == 0:
shipped_quantity = Decimal(str(r.r_lot_matched)).quantize(Decimal("0.00001"))
if self.ship.shipment == 'in':
if not self.ship.shipment_in:
UserError("Shipment not known!")
shipment_origin = 'stock.shipment.in,'+str(self.ship.shipment_in.id)
elif self.ship.shipment == 'out':
if not self.ship.shipment_out:
UserError("Shipment not known!")
shipment_origin = 'stock.shipment.out,'+str(self.ship.shipment_out.id)
elif self.ship.shipment == 'int':
if not self.ship.shipment_internal:
UserError("Shipment not known!")
shipment_origin = 'stock.shipment.internal,'+str(self.ship.shipment_internal.id)
if r.id < 10000000 :
l = Lot(r.id)
logger.info("IN_SHIPPING1:%s",l)
if self.ship.shipment == 'in':
l.lot_shipment_in = self.ship.shipment_in
elif self.ship.shipment == 'out':
l.lot_shipment_out = self.ship.shipment_out
elif self.ship.shipment == 'int':
l.lot_shipment_internal = self.ship.shipment_internal
logger.info("IN_SHIPPING2:%s",l.move)
if not l.move:
continue
logger.info("IN_SHIPPING3:%s",r)
move = Move(l.move)
move.shipment = shipment_origin
Move.save([move])
linked_transit_move = move.get_linked_transit_move()
if linked_transit_move:
linked_transit_move.shipment = shipment_origin
Move.save([linked_transit_move])
#Decrease forecasted virtual part shipped
vlot_p = l.getVlot_p()
l.updateVirtualPart(-l.get_current_quantity_converted(),shipment_origin,l.getVlot_s())
l.lot_av = 'reserved'
Lot.save([l])
l.set_current_quantity(l.lot_quantity,l.lot_gross_quantity,2)
Lot.save([l])
if l.line:
affected_lines.append(l.line)
if l.sale_line:
affected_lines.append(l.sale_line)
else:
lqt = LotQt(r.id - 10000000)
#Increase forecasted virtual part shipped
if not lqt.lot_p.updateVirtualPart(shipped_quantity,shipment_origin,lqt.lot_s):
logger.info("LotShipping2:%s",shipped_quantity)
lqt.lot_p.createVirtualPart(shipped_quantity,shipment_origin,lqt.lot_s)
#Decrease forecasted virtual part non shipped
lqt.lot_p.updateVirtualPart(-shipped_quantity,None,lqt.lot_s)
if lqt.lot_p and lqt.lot_p.line:
affected_lines.append(lqt.lot_p.line)
if lqt.lot_s and lqt.lot_s.sale_line:
affected_lines.append(lqt.lot_s.sale_line)
Lot.assert_lines_quantity_consistency(affected_lines)
return 'end'
@@ -2784,13 +2789,14 @@ class LotMatching(Wizard):
def transition_matching(self):
Warning = Pool().get('res.user.warning')
LotQt = Pool().get('lot.qt')
if self.match.tot_p != self.match.tot_s:
warning_name = Warning.format("Quantity's issue", [])
if Warning.check(warning_name):
raise QtWarning(warning_name,
"Quantities not compatibles")
if self.match.tot_p != self.match.tot_s:
warning_name = Warning.format("Quantity's issue", [])
if Warning.check(warning_name):
raise QtWarning(warning_name,
"Quantities not compatibles")
Lot = Pool().get('lot.lot')
LotQt.match_lots(self.match.lot_p,self.match.lot_s)
with Lot.skip_quantity_consistency():
LotQt.match_lots(self.match.lot_p,self.match.lot_s)
affected_lines = []
for matched_lot in list(self.match.lot_p or []) + list(self.match.lot_s or []):
if matched_lot.lot_id:
@@ -2974,42 +2980,43 @@ class LotUnmatch(Wizard):
Lot = Pool().get('lot.lot')
LotQt = Pool().get('lot.qt')
affected_lines = []
for r in self.records:
if r.id > 10000000 :
lqt = LotQt(r.id - 10000000)
if lqt.lot_p and lqt.lot_s:
lot = lqt.lot_p
qt = lqt.lot_quantity
#Increase forecasted virtual parts non matched
if not lot.updateVirtualPart(qt,lqt.lot_shipment_origin,None):
lot.createVirtualPart(qt,lqt.lot_shipment_origin,None)
if not lot.updateVirtualPart(qt,lqt.lot_shipment_origin,lqt.lot_s,'only sale'):
lot.createVirtualPart(qt,lqt.lot_shipment_origin,lqt.lot_s,'only sale')
#Decrease forecasted virtual part matched
logger.info("UNMATCH_QT:%s",qt)
lot.updateVirtualPart(-qt,lqt.lot_shipment_origin,lqt.lot_s)
if lqt.lot_p and lqt.lot_p.line:
affected_lines.append(lqt.lot_p.line)
if lqt.lot_s and lqt.lot_s.sale_line:
affected_lines.append(lqt.lot_s.sale_line)
else:
lot = Lot(r.id)
qt = lot.get_current_quantity_converted()
# #Increase forecasted virtual part matched
# if not lot.updateVirtualPart(qt,lot.lot_shipment_origin,lot.getVlot_s()):
# lot.createVirtualPart(qt,lot.lot_shipment_origin,lot.getVlot_s())
# #Decrease forecasted virtual part non matched
# if not lot.updateVirtualPart(-qt,lot.lot_shipment_origin,None):
# lot.createVirtualPart(-qt,lot.lot_shipment_origin,None)
ls = lot.getVlot_s()
ls.lot_quantity += qt
Lot.save([ls])
lot.sale_line = None
Lot.save([lot])
if lot.line:
affected_lines.append(lot.line)
if ls.sale_line:
affected_lines.append(ls.sale_line)
with Lot.skip_quantity_consistency():
for r in self.records:
if r.id > 10000000 :
lqt = LotQt(r.id - 10000000)
if lqt.lot_p and lqt.lot_s:
lot = lqt.lot_p
qt = lqt.lot_quantity
#Increase forecasted virtual parts non matched
if not lot.updateVirtualPart(qt,lqt.lot_shipment_origin,None):
lot.createVirtualPart(qt,lqt.lot_shipment_origin,None)
if not lot.updateVirtualPart(qt,lqt.lot_shipment_origin,lqt.lot_s,'only sale'):
lot.createVirtualPart(qt,lqt.lot_shipment_origin,lqt.lot_s,'only sale')
#Decrease forecasted virtual part matched
logger.info("UNMATCH_QT:%s",qt)
lot.updateVirtualPart(-qt,lqt.lot_shipment_origin,lqt.lot_s)
if lqt.lot_p and lqt.lot_p.line:
affected_lines.append(lqt.lot_p.line)
if lqt.lot_s and lqt.lot_s.sale_line:
affected_lines.append(lqt.lot_s.sale_line)
else:
lot = Lot(r.id)
qt = lot.get_current_quantity_converted()
# #Increase forecasted virtual part matched
# if not lot.updateVirtualPart(qt,lot.lot_shipment_origin,lot.getVlot_s()):
# lot.createVirtualPart(qt,lot.lot_shipment_origin,lot.getVlot_s())
# #Decrease forecasted virtual part non matched
# if not lot.updateVirtualPart(-qt,lot.lot_shipment_origin,None):
# lot.createVirtualPart(-qt,lot.lot_shipment_origin,None)
ls = lot.getVlot_s()
ls.lot_quantity += qt
Lot.save([ls])
lot.sale_line = None
Lot.save([lot])
if lot.line:
affected_lines.append(lot.line)
if ls.sale_line:
affected_lines.append(ls.sale_line)
Lot.assert_lines_quantity_consistency(affected_lines)
return 'end'
@@ -3027,57 +3034,58 @@ class LotUnship(Wizard):
LotQt = Pool().get('lot.qt')
Move = Pool().get('stock.move')
affected_lines = []
for r in self.records:
lqt = LotQt(r.id - 10000000)
lot = Lot(r.id)
if lqt and r.r_lot_type == 'virtual':
shipment = None
qt = lqt.lot_quantity
mode = 'both'
if not lqt.lot_p:
lot = lqt.lot_s
mode = 'only sale'
else:
lot = lqt.lot_p
if lqt.lot_shipment_in:
shipment = lqt.lot_shipment_in
elif lqt.lot_shipment_internal:
shipment = lqt.lot_shipment_internal
elif lqt.lot_shipment_out:
shipment = lqt.lot_shipment_out
#Decrease forecasted virtual part shipped
lot.updateVirtualPart(-qt,lqt.lot_shipment_origin,lqt.lot_s,mode)
#Increase forecasted virtual part non shipped
if not lot.updateVirtualPart(qt,None,lqt.lot_s,mode):
lot.createVirtualPart(qt,None,lqt.lot_s,mode)
if lqt.lot_p and lqt.lot_p.line:
affected_lines.append(lqt.lot_p.line)
if lqt.lot_s and lqt.lot_s.sale_line:
affected_lines.append(lqt.lot_s.sale_line)
if lot and r.r_lot_type == 'physic':
lot = Lot(r.r_lot_p)
if lot.lot_type == 'physic':
str_sh = str(lot.lot_shipment_origin)
if 'stock.shipment.in' in str_sh:
lot.lot_shipment_in = None
elif 'stock.shipment.out' in str_sh:
lot.lot_shipment_out = None
elif 'stock.shipment.internal' in str_sh:
lot.lot_shipment_internal = None
if lot.move:
move = Move(lot.move)
move.shipment = None
Move.save([move])
# lm = LotMove.search([('lot','=',lot.id),('move','=',lot.move)])
# if lm:
# LotMove.delete(lm)
lot.lot_status = 'forecast'
Lot.save([lot])
if lot.line:
affected_lines.append(lot.line)
if lot.sale_line:
affected_lines.append(lot.sale_line)
with Lot.skip_quantity_consistency():
for r in self.records:
lqt = LotQt(r.id - 10000000)
lot = Lot(r.id)
if lqt and r.r_lot_type == 'virtual':
shipment = None
qt = lqt.lot_quantity
mode = 'both'
if not lqt.lot_p:
lot = lqt.lot_s
mode = 'only sale'
else:
lot = lqt.lot_p
if lqt.lot_shipment_in:
shipment = lqt.lot_shipment_in
elif lqt.lot_shipment_internal:
shipment = lqt.lot_shipment_internal
elif lqt.lot_shipment_out:
shipment = lqt.lot_shipment_out
#Decrease forecasted virtual part shipped
lot.updateVirtualPart(-qt,lqt.lot_shipment_origin,lqt.lot_s,mode)
#Increase forecasted virtual part non shipped
if not lot.updateVirtualPart(qt,None,lqt.lot_s,mode):
lot.createVirtualPart(qt,None,lqt.lot_s,mode)
if lqt.lot_p and lqt.lot_p.line:
affected_lines.append(lqt.lot_p.line)
if lqt.lot_s and lqt.lot_s.sale_line:
affected_lines.append(lqt.lot_s.sale_line)
if lot and r.r_lot_type == 'physic':
lot = Lot(r.r_lot_p)
if lot.lot_type == 'physic':
str_sh = str(lot.lot_shipment_origin)
if 'stock.shipment.in' in str_sh:
lot.lot_shipment_in = None
elif 'stock.shipment.out' in str_sh:
lot.lot_shipment_out = None
elif 'stock.shipment.internal' in str_sh:
lot.lot_shipment_internal = None
if lot.move:
move = Move(lot.move)
move.shipment = None
Move.save([move])
# lm = LotMove.search([('lot','=',lot.id),('move','=',lot.move)])
# if lm:
# LotMove.delete(lm)
lot.lot_status = 'forecast'
Lot.save([lot])
if lot.line:
affected_lines.append(lot.line)
if lot.sale_line:
affected_lines.append(lot.sale_line)
Lot.assert_lines_quantity_consistency(affected_lines)
return 'end'
@@ -3201,56 +3209,61 @@ class LotImporting(Wizard):
def transition_start(self):
return 'imp'
def transition_importing(self):
if self.records:
line = self.records[0].r_line
Lot = Pool().get('lot.lot')
LotQt = Pool().get('lot.qt')
def transition_importing(self):
if self.records:
line = self.records[0].r_line
Lot = Pool().get('lot.lot')
LotQt = Pool().get('lot.qt')
LotQtHist = Pool().get('lot.qt.hist')
LotQtType = Pool().get('lot.qt.type')
lqt = LotQt(self.records[0].id - 10000000)
tot_qt = 0
for l in self.imp.lots:
l.line = line
l.lot_shipment_in = self.records[0].r_lot_shipment_in
l.lot_shipment_internal = self.records[0].r_lot_shipment_internal
l.lot_shipment_out = self.records[0].r_lot_shipment_out
l.lot_product = self.records[0].r_lot_product
l.sale_line = self.records[0].r_sale_line
l.lot_type = 'physic'
premium = Decimal(0)
if l.lot_price:
premium = l.lot_price - l.line.unit_price
logger.info("IMPORTLOT:%s",l.line.linked_price)
if l.line.linked_price:
premium = l.lot_price - l.line.linked_price
l.lot_premium = premium
l.lot_premium_sup = premium
Uom = Pool().get('product.uom')
net_qt = round(Decimal(Uom.compute_qty(l.lot_unit_line, float(l.lot_quantity), line.unit)),5)
gross_qt = round(Decimal(Uom.compute_qty(l.lot_unit_line, float(l.lot_gross_quantity), line.unit)),5)
lqtt = LotQtType.search([('sequence','=',1)])
if lqtt:
lqh = LotQtHist()
lqh.quantity_type = lqtt[0]
lqh.quantity = l.lot_quantity
lqh.gross_quantity = l.lot_gross_quantity
l.lot_hist = [lqh]
Lot.save([l])
tot_qt += net_qt
logger.info("IMPORTING:%s",net_qt)
#need to decrease sale virtual lot if matching
if self.records[0].r_lot_s:
ls = Lot(self.records[0].r_lot_s)
ls.lot_quantity -= net_qt
ls.lot_gross_quantity -= net_qt
ls.lot_qt -= float(net_qt)
Lot.save([ls])
lqt.lot_quantity -= tot_qt
if lqt.lot_quantity < 0:
lqt.lot_quantity = 0
LotQt.save([lqt])
return 'end'
LotQtType = Pool().get('lot.qt.type')
lqt = LotQt(self.records[0].id - 10000000)
tot_qt = 0
affected_lines = [line]
if self.records[0].r_sale_line:
affected_lines.append(self.records[0].r_sale_line)
with Lot.skip_quantity_consistency():
for l in self.imp.lots:
l.line = line
l.lot_shipment_in = self.records[0].r_lot_shipment_in
l.lot_shipment_internal = self.records[0].r_lot_shipment_internal
l.lot_shipment_out = self.records[0].r_lot_shipment_out
l.lot_product = self.records[0].r_lot_product
l.sale_line = self.records[0].r_sale_line
l.lot_type = 'physic'
premium = Decimal(0)
if l.lot_price:
premium = l.lot_price - l.line.unit_price
logger.info("IMPORTLOT:%s",l.line.linked_price)
if l.line.linked_price:
premium = l.lot_price - l.line.linked_price
l.lot_premium = premium
l.lot_premium_sup = premium
Uom = Pool().get('product.uom')
net_qt = round(Decimal(Uom.compute_qty(l.lot_unit_line, float(l.lot_quantity), line.unit)),5)
gross_qt = round(Decimal(Uom.compute_qty(l.lot_unit_line, float(l.lot_gross_quantity), line.unit)),5)
lqtt = LotQtType.search([('sequence','=',1)])
if lqtt:
lqh = LotQtHist()
lqh.quantity_type = lqtt[0]
lqh.quantity = l.lot_quantity
lqh.gross_quantity = l.lot_gross_quantity
l.lot_hist = [lqh]
Lot.save([l])
tot_qt += net_qt
logger.info("IMPORTING:%s",net_qt)
#need to decrease sale virtual lot if matching
if self.records[0].r_lot_s:
ls = Lot(self.records[0].r_lot_s)
ls.lot_quantity -= net_qt
ls.lot_gross_quantity -= net_qt
ls.lot_qt -= float(net_qt)
Lot.save([ls])
lqt.lot_quantity -= tot_qt
if lqt.lot_quantity < 0:
lqt.lot_quantity = 0
LotQt.save([lqt])
Lot.assert_lines_quantity_consistency(affected_lines)
return 'end'
def end(self):
return 'reload'
@@ -3823,36 +3836,37 @@ class LotWeighing(Wizard):
Lot = Pool().get('lot.lot')
LotHist = Pool().get('lot.qt.hist')
affected_lines = []
for l in self.w.lot_p:
quantity = l.lot.get_current_quantity_converted()
lhs = LotHist.search([('lot',"=",l.lot.id),('quantity_type','=',self.w.lot_state.id)])
if lhs:
lh = lhs[0]
else:
lh = LotHist()
lh.lot = l.lot
lh.quantity_type = self.w.lot_state
lh.quantity = round(l.lot_quantity_new,5)
lh.gross_quantity = round(l.lot_gross_quantity_new,5)
LotHist.save([lh])
l.lot.lot_qt = l.lot_qt
if self.w.lot_update_state :
l.lot.lot_state = self.w.lot_state
Lot.save([l.lot])
diff = round(Decimal(l.lot.get_current_quantity_converted() - quantity),5)
if diff != 0 :
#need to update virtual part
l.lot.updateVirtualPart(-diff,l.lot.lot_shipment_origin,l.lot.getVlot_s())
if l.lot.line:
affected_lines.append(l.lot.line)
if l.lot.sale_line:
affected_lines.append(l.lot.sale_line)
#adjuts fee ordered with new quantity
fees = FeeLots.search(['lot','=',l.lot.id])
for f in fees:
f.fee.sync_quantity_from_lots()
f.fee.adjust_purchase_values()
with Lot.skip_quantity_consistency():
for l in self.w.lot_p:
quantity = l.lot.get_current_quantity_converted()
lhs = LotHist.search([('lot',"=",l.lot.id),('quantity_type','=',self.w.lot_state.id)])
if lhs:
lh = lhs[0]
else:
lh = LotHist()
lh.lot = l.lot
lh.quantity_type = self.w.lot_state
lh.quantity = round(l.lot_quantity_new,5)
lh.gross_quantity = round(l.lot_gross_quantity_new,5)
LotHist.save([lh])
l.lot.lot_qt = l.lot_qt
if self.w.lot_update_state :
l.lot.lot_state = self.w.lot_state
Lot.save([l.lot])
diff = round(Decimal(l.lot.get_current_quantity_converted() - quantity),5)
if diff != 0 :
#need to update virtual part
l.lot.updateVirtualPart(-diff,l.lot.lot_shipment_origin,l.lot.getVlot_s())
if l.lot.line:
affected_lines.append(l.lot.line)
if l.lot.sale_line:
affected_lines.append(l.lot.sale_line)
#adjuts fee ordered with new quantity
fees = FeeLots.search(['lot','=',l.lot.id])
for f in fees:
f.fee.sync_quantity_from_lots()
f.fee.adjust_purchase_values()
Lot.assert_lines_quantity_consistency(affected_lines)
return 'end'

View File

@@ -340,18 +340,113 @@ class ContractFactory:
qt = source['quantity']
if type_ == 'Purchase':
if cls._attach_or_split_source_lot_qt(source, lot, type_):
return
if not lot.updateVirtualPart(qt, shipment_origin, vlot):
lot.createVirtualPart(qt, shipment_origin, vlot)
# Decrease forecasted virtual part non matched
lot.updateVirtualPart(-qt, shipment_origin, vlot, 'only sale')
else:
if cls._attach_or_split_source_lot_qt(source, lot, type_):
return
if not vlot.updateVirtualPart(qt, shipment_origin, lot):
vlot.createVirtualPart(qt, shipment_origin, lot)
# Decrease forecasted virtual part non matched
vlot.updateVirtualPart(-qt, shipment_origin, None)
@classmethod
def _attach_or_split_source_lot_qt(cls, source, new_virtual_lot, type_):
"""Reuse the selected forecast line instead of create/decrease."""
pool = Pool()
LotQt = pool.get('lot.qt')
quantity = cls._normalize_quantity(source['quantity'])
source_lqt = source.get('lqt')
if not source_lqt:
source_lqt = cls._find_source_lot_qt(source, type_)
if not source_lqt:
return False
remaining = cls._normalize_quantity(source_lqt.lot_quantity) - quantity
if remaining < 0:
return False
if remaining:
matched_lqt = LotQt()
matched_lqt.lot_p = (
new_virtual_lot.id
if type_ == 'Purchase'
else source_lqt.lot_p)
matched_lqt.lot_s = (
source_lqt.lot_s
if type_ == 'Purchase'
else new_virtual_lot.id)
matched_lqt.lot_shipment_in = source_lqt.lot_shipment_in
matched_lqt.lot_shipment_internal = source_lqt.lot_shipment_internal
matched_lqt.lot_shipment_out = source_lqt.lot_shipment_out
matched_lqt.lot_move = source_lqt.lot_move
matched_lqt.lot_av = source_lqt.lot_av
matched_lqt.lot_status = source_lqt.lot_status
matched_lqt.lot_unit = source_lqt.lot_unit
matched_lqt.lot_quantity = quantity
source_lqt.lot_quantity = remaining
LotQt.save([source_lqt, matched_lqt])
else:
if type_ == 'Purchase':
source_lqt.lot_p = new_virtual_lot.id
else:
source_lqt.lot_s = new_virtual_lot.id
LotQt.save([source_lqt])
return True
@classmethod
def _find_source_lot_qt(cls, source, type_):
pool = Pool()
LotQt = pool.get('lot.qt')
lot = source.get('lot')
if not lot:
return None
domain = []
if type_ == 'Purchase':
domain.extend([
('lot_s', '=', lot.id),
('lot_p', '=', None),
])
else:
domain.extend([
('lot_p', '=', lot.id),
('lot_s', '=', None),
])
cls._add_shipment_domain(domain, source.get('shipment_origin'))
domain.append(('lot_quantity', '!=', 0))
lqts = LotQt.search(domain)
quantity = cls._normalize_quantity(source['quantity'])
for lqt in lqts:
if cls._normalize_quantity(lqt.lot_quantity) >= quantity:
return lqt
return None
@staticmethod
def _add_shipment_domain(domain, shipment_origin):
domain.extend([
('lot_shipment_in', '=', None),
('lot_shipment_internal', '=', None),
('lot_shipment_out', '=', None),
])
if not shipment_origin:
return
model, record_id = shipment_origin.split(',', 1)
record_id = int(record_id)
if model == 'stock.shipment.in':
domain[-3] = ('lot_shipment_in', '=', record_id)
elif model == 'stock.shipment.internal':
domain[-2] = ('lot_shipment_internal', '=', record_id)
elif model == 'stock.shipment.out':
domain[-1] = ('lot_shipment_out', '=', record_id)
@staticmethod
def _get_shipment_origin(ct):
if ct.shipment_in: