feat: add x_fc_authorizer_number, x_fc_account_number, x_marked_for fields; auto-link authorizer from XML
- fusion_claims: added x_fc_authorizer_number to res.partner for ADP authorizer registration numbers - fusion_claims: XML parser auto-links authorizer contact to sale order by ADP number - fusion_claims: removed size=9 constraint from x_fc_odsp_member_id - fusion_claims: authorizer number shown on OT/PT contact form - fusion_so_to_po: added x_marked_for (Many2one) field definition on purchase.order - fusion_so_to_po: added x_fc_account_number on res.partner for vendor account numbers
This commit is contained in:
4
fusion_so_to_po/wizard/__init__.py
Normal file
4
fusion_so_to_po/wizard/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import fusion_purchase_order_wiz
|
||||
from . import fusion_match_sale_order_wiz
|
||||
54
fusion_so_to_po/wizard/fusion_match_sale_order_wiz.py
Normal file
54
fusion_so_to_po/wizard/fusion_match_sale_order_wiz.py
Normal file
@@ -0,0 +1,54 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class FusionMatchSaleOrderWiz(models.TransientModel):
|
||||
_name = 'fusion.match.so.wiz'
|
||||
_description = 'Fusion - Match Sale Order Wizard'
|
||||
|
||||
fusion_po_id = fields.Many2one(
|
||||
'purchase.order',
|
||||
string='Purchase Order',
|
||||
required=True,
|
||||
readonly=True,
|
||||
)
|
||||
fusion_sale_order_id = fields.Many2one(
|
||||
'sale.order',
|
||||
string='Sale Order',
|
||||
help='Select the Sale Order to link to this Purchase Order',
|
||||
)
|
||||
fusion_search_hint = fields.Char(
|
||||
string='Search Hint',
|
||||
readonly=True,
|
||||
help='Suggested search term based on Marked For field',
|
||||
)
|
||||
|
||||
def action_fusion_confirm(self):
|
||||
self.ensure_one()
|
||||
|
||||
if not self.fusion_sale_order_id:
|
||||
raise UserError(_("Please select a Sale Order."))
|
||||
|
||||
customer = self.fusion_sale_order_id.partner_id
|
||||
|
||||
self.fusion_po_id.write({
|
||||
'fusion_sale_ids': [(4, self.fusion_sale_order_id.id)],
|
||||
'fusion_marked_for_ids': [(4, customer.id)],
|
||||
})
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'display_notification',
|
||||
'params': {
|
||||
'title': _('Success'),
|
||||
'message': _('Linked Purchase Order %s to Sale Order %s') % (
|
||||
self.fusion_po_id.name,
|
||||
self.fusion_sale_order_id.name,
|
||||
),
|
||||
'type': 'success',
|
||||
'sticky': False,
|
||||
'next': {'type': 'ir.actions.act_window_close'},
|
||||
},
|
||||
}
|
||||
43
fusion_so_to_po/wizard/fusion_match_sale_order_wiz.xml
Normal file
43
fusion_so_to_po/wizard/fusion_match_sale_order_wiz.xml
Normal file
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
|
||||
<record id="fusion_view_match_sale_order_wizard" model="ir.ui.view">
|
||||
<field name="name">fusion.match.so.wiz.form</field>
|
||||
<field name="model">fusion.match.so.wiz</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Match Sale Order">
|
||||
<field name="fusion_po_id" invisible="1"/>
|
||||
|
||||
<group>
|
||||
<p class="text-muted" colspan="2">
|
||||
Search and select the Sale Order to link to this Purchase Order.
|
||||
</p>
|
||||
</group>
|
||||
|
||||
<group>
|
||||
<field name="fusion_search_hint" string="Suggested Search" invisible="not fusion_search_hint"/>
|
||||
<field name="fusion_sale_order_id"
|
||||
string="Sale Order"
|
||||
options="{'no_create': True, 'no_quick_create': True}"
|
||||
context="{'search_default_name': fusion_search_hint}"/>
|
||||
</group>
|
||||
|
||||
<footer>
|
||||
<button name="action_fusion_confirm" string="Link Sale Order" type="object" class="btn-primary"/>
|
||||
<button special="cancel" string="Cancel" class="btn-secondary"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_action_match_sale_order_wizard" model="ir.actions.act_window">
|
||||
<field name="name">Match Sale Order</field>
|
||||
<field name="res_model">fusion.match.so.wiz</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
191
fusion_so_to_po/wizard/fusion_purchase_order_wiz.py
Normal file
191
fusion_so_to_po/wizard/fusion_purchase_order_wiz.py
Normal file
@@ -0,0 +1,191 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.exceptions import UserError
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
class FusionPurchaseOrderWiz(models.TransientModel):
|
||||
_name = 'fusion.so.po.wiz'
|
||||
_description = 'Fusion - Create Purchase Order Wizard'
|
||||
|
||||
fusion_so_id = fields.Many2one('sale.order', string='Sale Order')
|
||||
fusion_line_ids = fields.One2many(
|
||||
'fusion.so.po.line.wiz',
|
||||
'fusion_wizard_id',
|
||||
string='Products',
|
||||
)
|
||||
fusion_batch_vendor_id = fields.Many2one(
|
||||
'res.partner',
|
||||
string='Assign Vendor to All',
|
||||
domain="[('is_company', '=', True)]",
|
||||
help='Select a vendor here to assign it to ALL products at once',
|
||||
)
|
||||
|
||||
@api.onchange('fusion_batch_vendor_id')
|
||||
def _onchange_fusion_batch_vendor_id(self):
|
||||
if self.fusion_batch_vendor_id:
|
||||
selected_lines = self.fusion_line_ids.filtered(lambda l: l.selected)
|
||||
lines_to_update = selected_lines if selected_lines else self.fusion_line_ids
|
||||
|
||||
for line in lines_to_update:
|
||||
line.vendor_id = self.fusion_batch_vendor_id
|
||||
if line.product_id:
|
||||
seller = line.product_id.seller_ids.filtered(
|
||||
lambda s: s.partner_id.id == self.fusion_batch_vendor_id.id
|
||||
)[:1]
|
||||
if seller and seller.price:
|
||||
line.price_unit = seller.price
|
||||
else:
|
||||
line.price_unit = line.product_id.standard_price
|
||||
line.price_subtotal = line.price_unit * line.product_uom_qty
|
||||
|
||||
for line in selected_lines:
|
||||
line.selected = False
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields_list):
|
||||
res = super().default_get(fields_list)
|
||||
active_ids = self._context.get('active_ids')
|
||||
if not active_ids:
|
||||
return res
|
||||
|
||||
sale_order = self.env['sale.order'].browse(active_ids[0])
|
||||
if not sale_order.order_line:
|
||||
raise UserError(_("Please add some valid sale order lines...!"))
|
||||
|
||||
res['fusion_so_id'] = sale_order.id
|
||||
|
||||
product_lines = []
|
||||
for line in sale_order.order_line:
|
||||
if line.display_type in ('line_section', 'line_note'):
|
||||
continue
|
||||
|
||||
description = line.name or line.product_id.display_name or line.product_id.name or 'Product'
|
||||
|
||||
cost_price = line.product_id.standard_price
|
||||
product_lines.append((0, 0, {
|
||||
'product_id': line.product_id.id,
|
||||
'description': description,
|
||||
'product_uom_qty': line.product_uom_qty,
|
||||
'price_unit': cost_price,
|
||||
'product_uom': line.product_uom_id.id,
|
||||
'price_subtotal': cost_price * line.product_uom_qty,
|
||||
'fusion_so_line_id': line.id,
|
||||
'vendor_id': False,
|
||||
}))
|
||||
|
||||
res['fusion_line_ids'] = product_lines
|
||||
return res
|
||||
|
||||
def fusion_create_po(self):
|
||||
self.ensure_one()
|
||||
|
||||
vendor_products = defaultdict(list)
|
||||
for product_line in self.fusion_line_ids:
|
||||
if product_line.vendor_id:
|
||||
vendor_products[product_line.vendor_id.id].append(product_line)
|
||||
|
||||
if not vendor_products:
|
||||
raise UserError(_("Please assign at least one product to a vendor before creating Purchase Orders."))
|
||||
|
||||
now = fields.Datetime.now()
|
||||
created_pos = self.env['purchase.order']
|
||||
customer = self.fusion_so_id.partner_id
|
||||
|
||||
for vendor_id, product_lines in vendor_products.items():
|
||||
partner = self.env['res.partner'].browse(vendor_id)
|
||||
fpos = self.env['account.fiscal.position'].sudo()._get_fiscal_position(partner)
|
||||
|
||||
date_planned = self.fusion_so_id.commitment_date or now
|
||||
|
||||
purchase_order = self.env['purchase.order'].create({
|
||||
'partner_id': partner.id,
|
||||
'partner_ref': partner.ref,
|
||||
'company_id': self.fusion_so_id.company_id.id,
|
||||
'currency_id': self.env.company.currency_id.id,
|
||||
'dest_address_id': False,
|
||||
'origin': self.fusion_so_id.name,
|
||||
'payment_term_id': partner.property_supplier_payment_term_id.id,
|
||||
'date_order': now,
|
||||
'fiscal_position_id': fpos.id,
|
||||
'fusion_sale_ids': [(4, self.fusion_so_id.id)],
|
||||
'fusion_marked_for_ids': [(4, customer.id)],
|
||||
})
|
||||
|
||||
for product_line in product_lines:
|
||||
values = product_line._prepare_fusion_po_line(purchase_order, date_planned)
|
||||
self.env['purchase.order.line'].create(values)
|
||||
|
||||
created_pos |= purchase_order
|
||||
|
||||
if len(created_pos) == 1:
|
||||
return {
|
||||
'name': _('Purchase Order'),
|
||||
'view_mode': 'form',
|
||||
'res_model': 'purchase.order',
|
||||
'view_id': self.env.ref('purchase.purchase_order_form').id,
|
||||
'res_id': created_pos.id,
|
||||
'type': 'ir.actions.act_window',
|
||||
'target': 'current',
|
||||
}
|
||||
return {
|
||||
'name': _('Purchase Orders'),
|
||||
'view_mode': 'list,form',
|
||||
'res_model': 'purchase.order',
|
||||
'domain': [('id', 'in', created_pos.ids)],
|
||||
'type': 'ir.actions.act_window',
|
||||
'target': 'current',
|
||||
}
|
||||
|
||||
|
||||
class FusionPurchaseProductWiz(models.TransientModel):
|
||||
_name = 'fusion.so.po.line.wiz'
|
||||
_description = 'Fusion - Purchase Product Wizard Line'
|
||||
|
||||
fusion_wizard_id = fields.Many2one('fusion.so.po.wiz', string='Wizard', ondelete='cascade')
|
||||
selected = fields.Boolean(string='Select', default=False)
|
||||
fusion_so_line_id = fields.Many2one('sale.order.line', string='SO Line')
|
||||
product_id = fields.Many2one('product.product', string='Product')
|
||||
product_uom = fields.Many2one('uom.uom', string='Unit of Measure')
|
||||
description = fields.Char(string='Description')
|
||||
product_uom_qty = fields.Float(string='Quantity')
|
||||
price_unit = fields.Float(string='Unit Price')
|
||||
price_subtotal = fields.Float(string='Subtotal')
|
||||
vendor_id = fields.Many2one(
|
||||
'res.partner',
|
||||
string='Vendor',
|
||||
domain="[('is_company', '=', True)]",
|
||||
)
|
||||
|
||||
@api.onchange('vendor_id')
|
||||
def _onchange_vendor_id(self):
|
||||
if self.vendor_id and self.product_id:
|
||||
seller = self.product_id.seller_ids.filtered(
|
||||
lambda s: s.partner_id.id == self.vendor_id.id
|
||||
)[:1]
|
||||
if seller and seller.price:
|
||||
self.price_unit = seller.price
|
||||
else:
|
||||
self.price_unit = self.product_id.standard_price
|
||||
self.price_subtotal = self.price_unit * self.product_uom_qty
|
||||
|
||||
def _prepare_fusion_po_line(self, purchase_order, date_planned):
|
||||
self.ensure_one()
|
||||
product_uom = self.product_uom or self.product_id.uom_id
|
||||
|
||||
name = self.description
|
||||
if not name:
|
||||
name = self.product_id.display_name or self.product_id.name or 'Product'
|
||||
if self.product_id.default_code and self.product_id.default_code not in name:
|
||||
name = '[%s] %s' % (self.product_id.default_code, name)
|
||||
|
||||
return {
|
||||
'name': name,
|
||||
'product_qty': self.product_uom_qty,
|
||||
'product_id': self.product_id.id,
|
||||
'product_uom_id': product_uom.id,
|
||||
'price_unit': self.price_unit,
|
||||
'date_planned': date_planned,
|
||||
'order_id': purchase_order.id,
|
||||
}
|
||||
57
fusion_so_to_po/wizard/fusion_purchase_order_wiz.xml
Normal file
57
fusion_so_to_po/wizard/fusion_purchase_order_wiz.xml
Normal file
@@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
|
||||
<record id="fusion_view_purchase_order_wizard" model="ir.ui.view">
|
||||
<field name="name">fusion.so.po.wiz.form</field>
|
||||
<field name="model">fusion.so.po.wiz</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Create Purchase Orders">
|
||||
<field name="fusion_so_id" invisible="1"/>
|
||||
|
||||
<group>
|
||||
<group string="Assign Vendor to Selected">
|
||||
<field name="fusion_batch_vendor_id" options="{'no_create': True}" placeholder="Select vendor to assign..."/>
|
||||
</group>
|
||||
<group>
|
||||
<p class="text-muted mt-4">
|
||||
<b>Tip:</b> Check the boxes below to select products, then pick a vendor above to assign to selected only.
|
||||
If nothing is selected, vendor applies to all.
|
||||
</p>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<separator/>
|
||||
|
||||
<field name="fusion_line_ids" nolabel="1">
|
||||
<list editable="bottom" create="false">
|
||||
<field name="selected" string="Select"/>
|
||||
<field name="vendor_id" string="Vendor" placeholder="Select vendor..." widget="many2one" options="{'no_create': True, 'no_quick_create': True}"/>
|
||||
<field name="product_id" string="Product" readonly="1" force_save="1"/>
|
||||
<field name="description" string="Description" readonly="1" force_save="1" column_invisible="1"/>
|
||||
<field name="product_uom_qty" string="Qty" readonly="1" force_save="1"/>
|
||||
<field name="product_uom" string="UoM" readonly="1" force_save="1" groups="uom.group_uom" optional="hide"/>
|
||||
<field name="price_unit" string="Unit Price" force_save="1"/>
|
||||
<field name="price_subtotal" string="Subtotal" readonly="1" force_save="1"/>
|
||||
<field name="fusion_so_line_id" column_invisible="1" force_save="1"/>
|
||||
</list>
|
||||
</field>
|
||||
|
||||
<footer>
|
||||
<button name="fusion_create_po" string="Create Purchase Orders" type="object" class="btn-primary"/>
|
||||
<button special="cancel" string="Cancel" class="btn-secondary"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_purchase_order_wizard_action" model="ir.actions.act_window">
|
||||
<field name="name">Create Purchase Order</field>
|
||||
<field name="res_model">fusion.so.po.wiz</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user