2026-09-21 16:43:23 +05:30

82 lines
4.0 KiB
Python

# -*- coding: utf-8 -*-
from odoo import models, fields, api, _
from odoo.exceptions import UserError
class GarmentDispatch(models.Model):
_name = 'garment.dispatch'
_inherit = ['mail.thread', 'mail.activity.mixin']
_description = 'Garment Dispatch & Delivery Management'
_order = 'name desc'
name = fields.Char(string='Dispatch Order No', required=True, default=lambda self: _('New'), copy=False, tracking=True)
customer_id = fields.Many2one('res.partner', string='Buyer / Consignee', required=True, tracking=True)
sale_order_id = fields.Many2one('sale.order', string='Sales Order Ref', tracking=True)
production_plan_id = fields.Many2one('garment.production.plan', string='Production Plan Ref', tracking=True)
company_id = fields.Many2one('res.company', string='Company', default=lambda self: self.env.company)
# Dates & Logistics
date_dispatch = fields.Date(string='Dispatch Date', default=fields.Date.today, tracking=True)
carrier_name = fields.Char(string='Carrier / Shipping Line')
bl_awb_no = fields.Char(string='B/L or Air Waybill No', tracking=True)
container_no = fields.Char(string='Container No (FCL)')
seal_no = fields.Char(string='Customs Seal No')
vehicle_no = fields.Char(string='Truck / Vehicle Registration No')
port_of_loading = fields.Char(string='Port of Loading', default='Tuticorin / Chennai Port')
port_of_discharge = fields.Char(string='Port of Discharge')
# Cartons & Metrics
carton_ids = fields.One2many('garment.carton', 'dispatch_id', string='Dispatched Cartons')
total_cartons = fields.Integer(string='Total Cartons', compute='_compute_totals', store=True)
total_pieces = fields.Integer(string='Total Garments Dispatched', compute='_compute_totals', store=True)
total_gross_weight = fields.Float(string='Total Gross Weight (Kg)', compute='_compute_totals', store=True)
total_cbm = fields.Float(string='Total CBM (m³)', compute='_compute_totals', store=True)
state = fields.Selection([
('draft', 'Draft Shipment'),
('packed', 'Loaded & Ready to Depart'),
('dispatched', 'Dispatched / In Transit'),
('delivered', 'Delivered to Customer'),
('cancelled', 'Cancelled'),
], string='Status', default='draft', tracking=True, required=True)
notes = fields.Text(string='Shipping Instructions / Marks & Numbers')
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if vals.get('name', _('New')) == _('New'):
vals['name'] = self.env['ir.sequence'].next_by_code('garment.dispatch') or _('DISP/%s') % fields.Date.today().strftime('%Y%m%d')
return super(GarmentDispatch, self).create(vals_list)
@api.depends('carton_ids.total_pieces', 'carton_ids.gross_weight_kg', 'carton_ids.cbm')
def _compute_totals(self):
for rec in self:
rec.total_cartons = len(rec.carton_ids)
rec.total_pieces = sum(rec.carton_ids.mapped('total_pieces'))
rec.total_gross_weight = round(sum(rec.carton_ids.mapped('gross_weight_kg')), 2)
rec.total_cbm = round(sum(rec.carton_ids.mapped('cbm')), 3)
def action_dispatch(self):
"""Dispatches the shipment, deducts Finished Goods inventory"""
self.ensure_one()
if not self.carton_ids:
raise UserError(_("Please attach cartons to dispatch."))
FG = self.env['garment.finished.goods']
for ctn in self.carton_ids:
for line in ctn.line_ids:
fg = FG.search([
('style_id', '=', ctn.style_id.id),
('color_id', '=', line.color_id.id),
('size_id', '=', line.size_id.id),
], limit=1)
if fg:
fg.write({
'on_hand_qty': max(0, fg.on_hand_qty - line.quantity),
'shipped_qty': fg.shipped_qty + line.quantity,
})
self.write({'state': 'dispatched'})
def action_mark_delivered(self):
self.write({'state': 'delivered'})