This commit is contained in:
gsinghpal
2026-05-21 03:37:25 -04:00
parent b2f483d67c
commit 1314f4581d
47 changed files with 5730 additions and 177 deletions

View File

@@ -1,2 +1,3 @@
# -*- coding: utf-8 -*-
from . import fp_label_manual_wizard
from . import fp_label_generate_wizard

View File

@@ -0,0 +1,106 @@
# -*- coding: utf-8 -*-
# Copyright 2026 Nexa Systems Inc.
# License OPL-1 (Odoo Proprietary License v1.0)
"""Service-type confirmation wizard.
Opens when fp.receiving.action_generate_outbound_label fires (assuming
a label hasn't already been generated). Forces the operator to look at
carrier + service tier + weight before the API call is made — cheaper
shipping decisions, no surprise charges, and a hard gate against the
accidental-double-click bug where every Generate click leaked a fresh
FedEx shipment + tracking number.
Picked service rides through to the FedEx API via the
`fp_service_type_override` context key (see CLAUDE.md).
"""
from odoo import _, fields, models
from odoo.exceptions import UserError
class FpLabelGenerateWizard(models.TransientModel):
_name = 'fp.label.generate.wizard'
_description = 'Fusion Plating — Confirm Label Generation'
receiving_id = fields.Many2one(
'fp.receiving', required=True, readonly=True, ondelete='cascade',
)
receiving_name = fields.Char(related='receiving_id.name', readonly=True)
carrier_id = fields.Many2one(
related='receiving_id.x_fc_carrier_id', readonly=True,
)
carrier_default_service = fields.Char(
compute='_compute_carrier_default_service',
string='Carrier Default',
help='What the carrier would use if no override is set.',
)
service_type = fields.Selection(
selection='_fp_get_service_type_selection',
string='Service Type',
help='Leave blank to use the carrier default shown above. Pick '
'a faster tier (Priority Overnight, 2Day, etc.) when the '
'customer is paying for expedited delivery.',
)
weight = fields.Float(string='Weight', digits=(10, 3), required=True)
weight_uom = fields.Selection(
related='receiving_id.x_fc_weight_uom', readonly=True,
)
length = fields.Float(string='Length', digits=(10, 2))
width = fields.Float(string='Width', digits=(10, 2))
height = fields.Float(string='Height', digits=(10, 2))
dim_uom = fields.Selection(
related='receiving_id.x_fc_dim_uom', readonly=True,
)
def _fp_get_service_type_selection(self):
# Single source of truth — pulls the curated list from
# fp.receiving so both the form dropdown and the wizard stay
# in sync. See fp.receiving._FP_USABLE_FEDEX_SERVICES.
Receiving = self.env.get('fp.receiving')
if Receiving is None:
return []
return Receiving._fp_get_service_type_selection()
def _compute_carrier_default_service(self):
for wiz in self:
carrier = wiz.carrier_id
if not carrier or 'fedex_rest_service_type' not in carrier._fields:
wiz.carrier_default_service = ''
continue
code = carrier.fedex_rest_service_type or ''
label = dict(
carrier._fields['fedex_rest_service_type'].selection
).get(code, code)
wiz.carrier_default_service = label or _('(none set)')
@classmethod
def _fp_default_from_receiving(cls, env, rec):
"""Build the wizard create-vals from a receiving record."""
return {
'receiving_id': rec.id,
'service_type': rec.x_fc_outbound_service_type or False,
'weight': rec.x_fc_weight or 0.0,
'length': rec.x_fc_length or 0.0,
'width': rec.x_fc_width or 0.0,
'height': rec.x_fc_height or 0.0,
}
def action_confirm(self):
"""Apply the operator's choices back to the receiving, then
delegate to fp.receiving._fp_actually_generate_outbound_label
which makes the API call. Wizard closes; result action is the
outbound shipment view (or the manual-fallback wizard on error).
"""
self.ensure_one()
rec = self.receiving_id
if not rec:
raise UserError(_('Wizard is detached from the receiving.'))
if not self.weight or self.weight <= 0:
raise UserError(_('Enter a non-zero weight before generating.'))
rec.write({
'x_fc_outbound_service_type': self.service_type or False,
'x_fc_weight': self.weight,
'x_fc_length': self.length,
'x_fc_width': self.width,
'x_fc_height': self.height,
})
return rec._fp_actually_generate_outbound_label()

View File

@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2026 Nexa Systems Inc.
License OPL-1 (Odoo Proprietary License v1.0)
Part of the Fusion Plating product family.
Service-type confirmation wizard. Pops up before every
"Generate Outbound Label" so the operator can pick the FedEx
service tier (or accept the carrier default) and double-check
weight/dimensions before any API call is made.
-->
<odoo>
<record id="view_fp_label_generate_wizard_form" model="ir.ui.view">
<field name="name">fp.label.generate.wizard.form</field>
<field name="model">fp.label.generate.wizard</field>
<field name="arch" type="xml">
<form string="Generate Outbound Label">
<sheet>
<div class="oe_title">
<h2>Generate Label —
<field name="receiving_name"
readonly="1" nolabel="1" class="oe_inline"/>
</h2>
</div>
<div class="alert alert-info" role="alert">
<i class="fa fa-info-circle me-2"/>
Confirm the service tier and package details before
the carrier API is called. Each generation creates
a billable shipment.
</div>
<group>
<group string="Carrier">
<field name="carrier_id" readonly="1"/>
<field name="carrier_default_service"
readonly="1"/>
<field name="service_type"
placeholder="Use carrier default"/>
</group>
<group string="Package">
<label for="weight"/>
<div class="o_row">
<field name="weight" class="oe_inline"/>
<field name="weight_uom" nolabel="1"
readonly="1" class="oe_inline"/>
</div>
<label for="length" string="Dimensions (L×W×H)"/>
<div class="o_row">
<field name="length" class="oe_inline"/>
<span>×</span>
<field name="width" class="oe_inline"/>
<span>×</span>
<field name="height" class="oe_inline"/>
<field name="dim_uom" nolabel="1"
readonly="1" class="oe_inline"/>
</div>
</group>
</group>
</sheet>
<footer>
<button name="action_confirm" type="object"
string="Generate Label" class="btn-primary"/>
<button string="Cancel" class="btn-secondary"
special="cancel"/>
</footer>
</form>
</field>
</record>
</odoo>