[imp] add batch invoicing, improve max_qty constraint
This commit is contained in:
parent
7e0e9e5862
commit
83ff3d9f67
8 changed files with 90 additions and 14 deletions
|
|
@ -3,7 +3,7 @@
|
||||||
"summary": "Add minimum and maximum order quantities to sale orders and use default packaging",
|
"summary": "Add minimum and maximum order quantities to sale orders and use default packaging",
|
||||||
"author": "BAKEUP",
|
"author": "BAKEUP",
|
||||||
"website": "https://www.bakeup.org",
|
"website": "https://www.bakeup.org",
|
||||||
"category": "Stock",
|
"category": "Sale",
|
||||||
"version": "16.0.0.0.1",
|
"version": "16.0.0.0.1",
|
||||||
"depends": ["sale", "sale_order_batch"],
|
"depends": ["sale", "sale_order_batch"],
|
||||||
"data": [
|
"data": [
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,11 @@ class SaleOrderLine(models.Model):
|
||||||
|
|
||||||
@api.constrains("product_uom_qty", "product_uom_max_qty")
|
@api.constrains("product_uom_qty", "product_uom_max_qty")
|
||||||
def _check_product_uom_qty(self):
|
def _check_product_uom_qty(self):
|
||||||
for record in self:
|
for order_line in self:
|
||||||
if record.product_uom_max_qty != 0 and record.product_uom_qty > record.product_uom_max_qty:
|
if order_line.product_uom_max_qty != 0 and order_line.product_uom_qty > order_line.product_uom_max_qty:
|
||||||
raise UserError(_("The quantity must be less than or equal to the maximum quantity."))
|
raise UserError(
|
||||||
|
_(
|
||||||
|
f"{order_line.order_id.name},{order_line.product_id.name}:"
|
||||||
|
"The quantity must be less than or equal to the maximum quantity."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,14 @@
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath
|
<xpath
|
||||||
expr="//field[@name='sale_order_line_ids']/tree/field[@name='product_uom_qty']"
|
expr="//field[@name='sale_order_line_ids']/tree/field[@name='product_uom_qty']"
|
||||||
position="after"
|
position="before"
|
||||||
>
|
>
|
||||||
<field name="product_uom_ordered_qty" optional="hide"/>
|
<field name="product_uom_ordered_qty" optional="hide"/>
|
||||||
|
</xpath>
|
||||||
|
<xpath
|
||||||
|
expr="//field[@name='sale_order_line_ids']/tree/field[@name='product_uom_qty']"
|
||||||
|
position="after"
|
||||||
|
>
|
||||||
<field name="product_uom_max_qty"/>
|
<field name="product_uom_max_qty"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,14 @@
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<xpath
|
<xpath
|
||||||
expr="//field[@name='sale_order_line_ids']/tree/field[@name='product_uom_qty']"
|
expr="//field[@name='sale_order_line_ids']/tree/field[@name='product_uom_qty']"
|
||||||
position="after"
|
position="before"
|
||||||
>
|
>
|
||||||
<field name="product_uom_ordered_qty" optional="hide"/>
|
<field name="product_uom_ordered_qty" optional="hide"/>
|
||||||
|
</xpath>
|
||||||
|
<xpath
|
||||||
|
expr="//field[@name='sale_order_line_ids']/tree/field[@name='product_uom_qty']"
|
||||||
|
position="after"
|
||||||
|
>
|
||||||
<field name="product_uom_max_qty"/>
|
<field name="product_uom_max_qty"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='product_ids']/tree" position="inside">
|
<xpath expr="//field[@name='product_ids']/tree" position="inside">
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,10 @@
|
||||||
<field name="model">sale.order</field>
|
<field name="model">sale.order</field>
|
||||||
<field name="inherit_id" ref="sale.view_order_form"/>
|
<field name="inherit_id" ref="sale.view_order_form"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<xpath expr="//field[@name='order_line']/tree/field[@name='product_uom_qty']" position="after">
|
<xpath expr="//field[@name='order_line']/tree/field[@name='product_uom_qty']" position="before">
|
||||||
<field name="product_uom_ordered_qty" optional="hide"/>
|
<field name="product_uom_ordered_qty" optional="hide"/>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//field[@name='order_line']/tree/field[@name='product_uom_qty']" position="after">
|
||||||
<field name="product_uom_max_qty"/>
|
<field name="product_uom_max_qty"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,8 @@ class SaleOrderBatch(models.Model):
|
||||||
sale_order_ids = fields.One2many("sale.order", "batch_id")
|
sale_order_ids = fields.One2many("sale.order", "batch_id")
|
||||||
sale_order_count = fields.Integer(compute="_compute_sale_order_count")
|
sale_order_count = fields.Integer(compute="_compute_sale_order_count")
|
||||||
sale_order_line_ids = fields.Many2many("sale.order.line", compute="_compute_sale_order_line_ids", store=True)
|
sale_order_line_ids = fields.Many2many("sale.order.line", compute="_compute_sale_order_line_ids", store=True)
|
||||||
|
invoice_ids = fields.Many2many("account.move", compute="_compute_invoice_ids")
|
||||||
|
invoice_count = fields.Integer(compute="_compute_invoice_ids")
|
||||||
amount_total = fields.Float(compute="_compute_amount_total", string="Total")
|
amount_total = fields.Float(compute="_compute_amount_total", string="Total")
|
||||||
product_ids = fields.One2many("sale.order.batch.product", "batch_id")
|
product_ids = fields.One2many("sale.order.batch.product", "batch_id")
|
||||||
product_count = fields.Integer(compute="_compute_product_count")
|
product_count = fields.Integer(compute="_compute_product_count")
|
||||||
|
|
@ -60,17 +62,24 @@ class SaleOrderBatch(models.Model):
|
||||||
else:
|
else:
|
||||||
batch.validity_date = False
|
batch.validity_date = False
|
||||||
|
|
||||||
@api.depends("sale_order_ids")
|
|
||||||
def _compute_sale_order_count(self):
|
|
||||||
for batch in self:
|
|
||||||
batch.sale_order_count = len(batch.sale_order_ids)
|
|
||||||
|
|
||||||
@api.depends("sale_order_ids.order_line")
|
@api.depends("sale_order_ids.order_line")
|
||||||
def _compute_sale_order_line_ids(self):
|
def _compute_sale_order_line_ids(self):
|
||||||
for batch in self:
|
for batch in self:
|
||||||
order_lines = self.env["sale.order.line"].search([("order_id", "in", batch.sale_order_ids.ids)])
|
order_lines = self.env["sale.order.line"].search([("order_id", "in", batch.sale_order_ids.ids)])
|
||||||
batch.sale_order_line_ids = order_lines
|
batch.sale_order_line_ids = order_lines
|
||||||
|
|
||||||
|
@api.depends("sale_order_ids")
|
||||||
|
def _compute_sale_order_count(self):
|
||||||
|
for batch in self:
|
||||||
|
batch.sale_order_count = len(batch.sale_order_ids)
|
||||||
|
|
||||||
|
@api.depends("sale_order_ids.invoice_ids")
|
||||||
|
def _compute_invoice_ids(self):
|
||||||
|
for batch in self:
|
||||||
|
invoices = batch.sale_order_ids.mapped("invoice_ids")
|
||||||
|
batch.invoice_ids = invoices
|
||||||
|
batch.invoice_count = len(invoices)
|
||||||
|
|
||||||
@api.depends("sale_order_ids.amount_total")
|
@api.depends("sale_order_ids.amount_total")
|
||||||
def _compute_amount_total(self):
|
def _compute_amount_total(self):
|
||||||
for batch in self:
|
for batch in self:
|
||||||
|
|
@ -113,6 +122,25 @@ class SaleOrderBatch(models.Model):
|
||||||
result = {"type": "ir.actions.act_window_close"}
|
result = {"type": "ir.actions.act_window_close"}
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def action_view_invoice(self):
|
||||||
|
invoices = self.mapped("invoice_ids")
|
||||||
|
action = self.env["ir.actions.actions"]._for_xml_id("account.action_move_out_invoice_type")
|
||||||
|
if len(invoices) > 1:
|
||||||
|
action["domain"] = [("id", "in", invoices.ids)]
|
||||||
|
elif len(invoices) == 1:
|
||||||
|
form_view = [(self.env.ref("account.view_move_form").id, "form")]
|
||||||
|
if "views" in action:
|
||||||
|
action["views"] = form_view + [(state, view) for state, view in action["views"] if view != "form"]
|
||||||
|
else:
|
||||||
|
action["views"] = form_view
|
||||||
|
action["res_id"] = invoices.id
|
||||||
|
else:
|
||||||
|
action = {"type": "ir.actions.act_window_close"}
|
||||||
|
|
||||||
|
context = {"default_move_type": "out_invoice"}
|
||||||
|
action["context"] = context
|
||||||
|
return action
|
||||||
|
|
||||||
def action_confirm(self):
|
def action_confirm(self):
|
||||||
for batch in self:
|
for batch in self:
|
||||||
orders = batch.with_context(bypass_batch=True).sale_order_ids
|
orders = batch.with_context(bypass_batch=True).sale_order_ids
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
<field name="sale_order_line_ids" widget="section_and_note_one2many">
|
<field name="sale_order_line_ids" widget="section_and_note_one2many">
|
||||||
<tree editable="bottom" create="0">
|
<tree editable="bottom" create="0">
|
||||||
<field name="sequence" widget="handle"/>
|
<field name="sequence" widget="handle"/>
|
||||||
|
<field name="name"/>
|
||||||
<field name="order_partner_id"/>
|
<field name="order_partner_id"/>
|
||||||
<field name="product_uom_qty"/>
|
<field name="product_uom_qty"/>
|
||||||
<field name="price_unit"/>
|
<field name="price_unit"/>
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,19 @@
|
||||||
type="object"
|
type="object"
|
||||||
attrs="{'invisible': [('state', '!=','open')]}"
|
attrs="{'invisible': [('state', '!=','open')]}"
|
||||||
/>
|
/>
|
||||||
|
<button
|
||||||
|
id="create_invoices"
|
||||||
|
name="%(sale.action_view_sale_advance_payment_inv)d"
|
||||||
|
string="Create Invoices"
|
||||||
|
type="action"
|
||||||
|
class="btn-primary"
|
||||||
|
context="{
|
||||||
|
'default_sale_order_ids': sale_order_ids,
|
||||||
|
}"
|
||||||
|
data-hotkey="q"
|
||||||
|
attrs="{'invisible': [('state', '!=', 'closed')]}"
|
||||||
|
/>
|
||||||
|
|
||||||
<field name="state" widget="statusbar" options="{'clickable': 'true'}"/>
|
<field name="state" widget="statusbar" options="{'clickable': 'true'}"/>
|
||||||
</header>
|
</header>
|
||||||
<div
|
<div
|
||||||
|
|
@ -58,6 +71,15 @@
|
||||||
>
|
>
|
||||||
<field string="Products" name="product_count" widget="statinfo"/>
|
<field string="Products" name="product_count" widget="statinfo"/>
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
name="action_view_invoice"
|
||||||
|
type="object"
|
||||||
|
class="oe_stat_button"
|
||||||
|
icon="fa-pencil-square-o"
|
||||||
|
attrs="{'invisible': [('invoice_count', '=', 0)]}"
|
||||||
|
>
|
||||||
|
<field name="invoice_count" widget="statinfo" string="Invoices"/>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<h1>
|
<h1>
|
||||||
<field name="name"/>
|
<field name="name"/>
|
||||||
|
|
@ -76,7 +98,6 @@
|
||||||
<field
|
<field
|
||||||
name="sale_order_ids"
|
name="sale_order_ids"
|
||||||
domain="[('state','in',['draft','sent']),('batch_id','=',False)]"
|
domain="[('state','in',['draft','sent']),('batch_id','=',False)]"
|
||||||
attrs="{'readonly': [('state', 'in', ('closed'))]}"
|
|
||||||
>
|
>
|
||||||
<tree>
|
<tree>
|
||||||
<field name="name"/>
|
<field name="name"/>
|
||||||
|
|
@ -84,6 +105,14 @@
|
||||||
<field name="date_order"/>
|
<field name="date_order"/>
|
||||||
<field name="amount_untaxed"/>
|
<field name="amount_untaxed"/>
|
||||||
<field name="amount_total"/>
|
<field name="amount_total"/>
|
||||||
|
<field
|
||||||
|
name="invoice_status"
|
||||||
|
decoration-success="invoice_status == 'invoiced'"
|
||||||
|
decoration-info="invoice_status == 'to invoice'"
|
||||||
|
decoration-warning="invoice_status == 'upselling'"
|
||||||
|
widget="badge"
|
||||||
|
optional="show"
|
||||||
|
/>
|
||||||
</tree>
|
</tree>
|
||||||
</field>
|
</field>
|
||||||
</page>
|
</page>
|
||||||
|
|
@ -95,8 +124,9 @@
|
||||||
>
|
>
|
||||||
<tree editable="bottom">
|
<tree editable="bottom">
|
||||||
<field name="sequence" widget="handle"/>
|
<field name="sequence" widget="handle"/>
|
||||||
|
<field name="order_id"/>
|
||||||
<field name="order_partner_id"/>
|
<field name="order_partner_id"/>
|
||||||
<field name="product_template_id"/>
|
<field name="product_template_id" optional="hide"/>
|
||||||
<field name="name"/>
|
<field name="name"/>
|
||||||
<field name="product_uom_qty"/>
|
<field name="product_uom_qty"/>
|
||||||
<field name="price_unit"/>
|
<field name="price_unit"/>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue