diff --git a/bemade_mailcow_integration/__manifest__.py b/bemade_mailcow_integration/__manifest__.py index df44301..466e33c 100644 --- a/bemade_mailcow_integration/__manifest__.py +++ b/bemade_mailcow_integration/__manifest__.py @@ -34,6 +34,7 @@ ], "assets": { "web.assets_backend": [ + # BV: Commented out the following lines to avoid errors when installing the module. # "bemade_mailcow_integration/static/src/js/mailcow.js", # "bemade_mailcow_integration/static/src/xml/mailcow_templates.xml", ], diff --git a/bemade_margin_vendor_pricelist/models/__init__.py b/bemade_margin_vendor_pricelist/models/__init__.py index 6aacb75..960f6f4 100644 --- a/bemade_margin_vendor_pricelist/models/__init__.py +++ b/bemade_margin_vendor_pricelist/models/__init__.py @@ -1 +1,2 @@ from . import sale_order +from . import sale_order_line \ No newline at end of file diff --git a/bemade_margin_vendor_pricelist/models/sale_order.py b/bemade_margin_vendor_pricelist/models/sale_order.py index 2b5252a..4f8f105 100644 --- a/bemade_margin_vendor_pricelist/models/sale_order.py +++ b/bemade_margin_vendor_pricelist/models/sale_order.py @@ -21,157 +21,3 @@ class SaleOrder(models.Model): order.margin_percent_actual = order.amount_untaxed and order.margin_actual / order.amount_untaxed -class SaleOrderLine(models.Model): - _inherit = 'sale.order.line' - - purchase_price_vendor = fields.Float( - compute='_compute_purchase_price_vendor', - string="Vendor Price", - groups="base.group_user", - digits='Product Price' - ) - - margin_percent_vendor = fields.Float( - string='Margin (%) on Vendor Price', - groups='base.group_user', - group_operator='avg', - compute='_compute_margin_vendor' - ) - - margin_vendor = fields.Float( - string='Margin on Vendor Price', - groups='base.group_user', - digits='Product Price', - compute='_compute_margin_vendor' - ) - - purchase_price_actual = fields.Float( - compute="_compute_actual_margins", - digits='Product Price', - groups="base.group_user", - string="Purchase Price" - ) - - margin_actual = fields.Float( - compute="_compute_actual_margins", - digits='Product Price', - groups="base.group_user", - string="Our Margin" - ) - - margin_percent_actual = fields.Float( - compute="_compute_actual_margins", - groups="base.group_user", - string="Our Margin (%)" - ) - - @api.depends( - 'purchase_price', - 'purchase_price_vendor', - 'move_ids.product_id', - 'move_ids.product_id.qty_available', - 'move_ids.state', - 'qty_to_deliver' - ) - def _compute_actual_margins(self): - """ We want to use the margin based on average inventory valuation when the - sale order line will be completely fulfilled (or has been fulfilled) from stock. - For product not yet in stock we want to use the vendor price. We can also have - blended calculations (partly on vendor price, partly on stock valuation). This - occurs when an order has been or would be partially fulfilled from available - stock. - :return: - """ - non_product_lines = self.filtered(lambda r: not r.product_id) - non_product_lines.purchase_price_actual = 0.0 - non_product_lines.margin_actual = 0.0 - non_product_lines.margin_percent_actual = 0.0 - for line in self - non_product_lines: - stock_missing = line._determine_missing_stock() - if float_is_zero(stock_missing, precision_rounding=line.product_uom.rounding): - # everything is coming from stock, use inventory valuation - line.purchase_price_actual = line.purchase_price - elif float_compare(line.product_uom_qty, stock_missing, - precision_rounding=line.product_uom.rounding) == 0: - # everything is coming from the vendor, use vendor pricing - line.purchase_price_actual = line.purchase_price_vendor - else: - # we have a mix, use blended pricing - qty_from_stock = line.product_uom_qty - stock_missing - line.purchase_price_actual = \ - (stock_missing * line.purchase_price_vendor - + qty_from_stock * line.purchase_price) \ - / line.product_uom_qty - line.margin_actual = line.price_subtotal - ( - line.purchase_price_actual * line.product_uom_qty) - line.margin_percent_actual = line.price_subtotal and line.margin_actual / line.price_subtotal - - def _determine_missing_stock(self) -> float: - """ Compute how much stock is missing to meet an order line's demand. In the - case of a quotation line, available stock is checked as if the order were to be - placed immediately. - - :return: The quantity missing from available stock to fulfill the line, in - the unit of measure matching self.product_uom. - """ - self.ensure_one() - is_order = self.order_id.state in ('sale', 'done') - if is_order and self.qty_to_deliver == 0: - return 0 - elif is_order and self.qty_to_deliver > 0: - reserved = sum([m.reserved_availability for m in self.move_ids]) - missing = self.qty_to_deliver - reserved - if float_compare(missing, 0.0, - precision_rounding=self.product_uom.rounding) == 1: - # Not enough reserved, check stock - missing = missing - self.product_id.qty_available - if float_compare(missing, 0.0, - precision_rounding=self.product_uom.rounding) == 1: - # Missing some stock to meet demand, return the quantity - return missing - else: - # Enough stock available to meet this line's demand - return 0 - else: - # Already have stock reserved - return 0 - else: - # This is a quotation, don't bother with stock reservations - missing = self.product_uom_qty - self.product_id.qty_available - if float_compare(missing, 0.0, - precision_rounding=self.product_uom.rounding) == 1: - return missing - else: - return 0 - - @api.depends('product_id', 'product_id.seller_ids', - 'product_id.seller_ids.price') - def _compute_purchase_price_vendor(self): - for line in self: - product = line.product_id - suppinfos = product.seller_ids.sorted('sequence') - if not suppinfos: - line.purchase_price_vendor = 0.0 - continue - suppinfo = suppinfos[0] - purch_currency = suppinfo.currency_id - to_cur = line.currency_id or line.order_id.currency_id - line.purchase_price_vendor = purch_currency._convert( - from_amount=suppinfo.price, - to_currency=to_cur, - company=line.company_id or self.env.company, - date=line.order_id.date_order or fields.Date.today(), - round=False, - ) if to_cur and suppinfo.price else suppinfo.price - - @api.depends('purchase_price_vendor') - def _compute_margin_vendor(self): - for line in self: - if not line.price_unit or float_is_zero(line.price_unit): - line.margin_vendor = 0 - line.margin_percent_vendor = 0 - continue - unit_margin = line.price_unit - line.purchase_price_vendor - line.margin_percent_vendor = unit_margin / line.price_unit - - line.margin_vendor = unit_margin * line.product_uom_qty diff --git a/bemade_margin_vendor_pricelist/models/sale_order_line.py b/bemade_margin_vendor_pricelist/models/sale_order_line.py new file mode 100644 index 0000000..b8b3b2b --- /dev/null +++ b/bemade_margin_vendor_pricelist/models/sale_order_line.py @@ -0,0 +1,158 @@ +from odoo import models, fields, api, _ +from odoo.tools.float_utils import float_is_zero, float_compare + + +class SaleOrderLine(models.Model): + _inherit = 'sale.order.line' + + purchase_price_vendor = fields.Float( + compute='_compute_purchase_price_vendor', + string="Vendor Price", + groups="base.group_user", + digits='Product Price' + ) + + margin_percent_vendor = fields.Float( + string='Margin (%) on Vendor Price', + groups='base.group_user', + group_operator='avg', + compute='_compute_margin_vendor' + ) + + margin_vendor = fields.Float( + string='Margin on Vendor Price', + groups='base.group_user', + digits='Product Price', + compute='_compute_margin_vendor' + ) + + purchase_price_actual = fields.Float( + compute="_compute_actual_margins", + digits='Product Price', + groups="base.group_user", + string="Purchase Price" + ) + + margin_actual = fields.Float( + compute="_compute_actual_margins", + digits='Product Price', + groups="base.group_user", + string="Our Margin" + ) + + margin_percent_actual = fields.Float( + compute="_compute_actual_margins", + groups="base.group_user", + string="Our Margin (%)" + ) + + @api.depends( + 'purchase_price', + 'purchase_price_vendor', + 'move_ids.product_id', + 'move_ids.product_id.qty_available', + 'move_ids.state', + 'qty_to_deliver' + ) + def _compute_actual_margins(self): + """ We want to use the margin based on average inventory valuation when the + sale order line will be completely fulfilled (or has been fulfilled) from stock. + For product not yet in stock we want to use the vendor price. We can also have + blended calculations (partly on vendor price, partly on stock valuation). This + occurs when an order has been or would be partially fulfilled from available + stock. + :return: + """ + non_product_lines = self.filtered(lambda r: not r.product_id) + non_product_lines.purchase_price_actual = 0.0 + non_product_lines.margin_actual = 0.0 + non_product_lines.margin_percent_actual = 0.0 + for line in self - non_product_lines: + stock_missing = line._determine_missing_stock() + if float_is_zero(stock_missing, precision_rounding=line.product_uom.rounding): + # everything is coming from stock, use inventory valuation + line.purchase_price_actual = line.purchase_price + elif float_compare(line.product_uom_qty, stock_missing, + precision_rounding=line.product_uom.rounding) == 0: + # everything is coming from the vendor, use vendor pricing + line.purchase_price_actual = line.purchase_price_vendor + else: + # we have a mix, use blended pricing + qty_from_stock = line.product_uom_qty - stock_missing + line.purchase_price_actual = \ + (stock_missing * line.purchase_price_vendor + + qty_from_stock * line.purchase_price) \ + / line.product_uom_qty + line.margin_actual = line.price_subtotal - ( + line.purchase_price_actual * line.product_uom_qty) + line.margin_percent_actual = line.price_subtotal and line.margin_actual / line.price_subtotal + + def _determine_missing_stock(self) -> float: + """ Compute how much stock is missing to meet an order line's demand. In the + case of a quotation line, available stock is checked as if the order were to be + placed immediately. + + :return: The quantity missing from available stock to fulfill the line, in + the unit of measure matching self.product_uom. + """ + self.ensure_one() + is_order = self.order_id.state in ('sale', 'done') + if is_order and self.qty_to_deliver == 0: + return 0 + elif is_order and self.qty_to_deliver > 0: + reserved = sum([m.reserved_availability for m in self.move_ids]) + missing = self.qty_to_deliver - reserved + if float_compare(missing, 0.0, + precision_rounding=self.product_uom.rounding) == 1: + # Not enough reserved, check stock + missing = missing - self.product_id.qty_available + if float_compare(missing, 0.0, + precision_rounding=self.product_uom.rounding) == 1: + # Missing some stock to meet demand, return the quantity + return missing + else: + # Enough stock available to meet this line's demand + return 0 + else: + # Already have stock reserved + return 0 + else: + # This is a quotation, don't bother with stock reservations + missing = self.product_uom_qty - self.product_id.qty_available + if float_compare(missing, 0.0, + precision_rounding=self.product_uom.rounding) == 1: + return missing + else: + return 0 + + @api.depends('product_id', 'product_id.seller_ids', + 'product_id.seller_ids.price') + def _compute_purchase_price_vendor(self): + for line in self: + product = line.product_id + suppinfos = product.seller_ids.sorted('sequence') + if not suppinfos: + line.purchase_price_vendor = 0.0 + continue + suppinfo = suppinfos[0] + purch_currency = suppinfo.currency_id + to_cur = line.currency_id or line.order_id.currency_id + line.purchase_price_vendor = purch_currency._convert( + from_amount=suppinfo.price, + to_currency=to_cur, + company=line.company_id or self.env.company, + date=line.order_id.date_order or fields.Date.today(), + round=False, + ) if to_cur and suppinfo.price else suppinfo.price + + @api.depends('purchase_price_vendor') + def _compute_margin_vendor(self): + for line in self: + if not line.price_unit or float_is_zero(line.price_unit): + line.margin_vendor = 0 + line.margin_percent_vendor = 0 + continue + unit_margin = line.price_unit - line.purchase_price_vendor + line.margin_percent_vendor = unit_margin / line.price_unit + + line.margin_vendor = unit_margin * line.product_uom_qty diff --git a/bemade_multiple_billing_contacts/__manifest__.py b/bemade_multiple_billing_contacts/__manifest__.py index 7c903b2..9ed2d59 100644 --- a/bemade_multiple_billing_contacts/__manifest__.py +++ b/bemade_multiple_billing_contacts/__manifest__.py @@ -17,22 +17,27 @@ # DEALINGS IN THE SOFTWARE. # { - 'name': 'bemade_multiple_billing_contacts', + 'name': 'Multiple Billing Contacts', 'version': '17.0.1.0.1', 'summary': 'Send invoices to multiple contacts by default.', - 'description': """By default, newly created invoices add all invoice addresses for the given partner as - followers on the invoice. If billing contacts are set manually on the sales order, those billing - contacts are added as followers on the invoice instead.""", + 'description': """ + By default, newly created invoices add all invoice addresses for the given partner as + followers on the invoice. If billing contacts are set manually on the sales order, those billing + contacts are added as followers on the invoice instead. + """, 'category': 'Invoicing Management', 'author': 'Bemade Inc.', 'website': 'https://www.bemade.org', 'license': 'OPL-1', - 'depends': ['sale', - 'account', - 'bemade_partner_root_ancestor', - ], - 'data': ['views/account_move_views.xml', - 'views/res_partner_views.xml'], + 'depends': [ + 'sale', + 'account', + 'bemade_partner_root_ancestor', + ], + 'data': [ + 'views/account_move_views.xml', + 'views/res_partner_views.xml' + ], 'demo': [], 'installable': True, 'auto_install': False, diff --git a/bemade_multiple_billing_contacts/models/account_move.py b/bemade_multiple_billing_contacts/models/account_move.py index 4dd3e2e..11d2aa0 100644 --- a/bemade_multiple_billing_contacts/models/account_move.py +++ b/bemade_multiple_billing_contacts/models/account_move.py @@ -4,11 +4,13 @@ from odoo import models, fields, api class AccountMove(models.Model): _inherit = 'account.move' - billing_contacts = fields.Many2many(comodel_name='res.partner', - string="Billing Contacts", - compute='_compute_billing_contacts', - inverse='_inverse_billing_contacts', - store=True,) + billing_contacts = fields.Many2many( + comodel_name='res.partner', + string="Billing Contacts", + compute='_compute_billing_contacts', + inverse='_inverse_billing_contacts', + store=True + ) @api.depends('line_ids.sale_line_ids.order_id', 'partner_id') def _compute_billing_contacts(self): diff --git a/bemade_multiple_billing_contacts/models/res_partner.py b/bemade_multiple_billing_contacts/models/res_partner.py index b31327b..a6c2b7a 100644 --- a/bemade_multiple_billing_contacts/models/res_partner.py +++ b/bemade_multiple_billing_contacts/models/res_partner.py @@ -4,12 +4,17 @@ from odoo import models, fields, api, _, Command class Partner(models.Model): _inherit = 'res.partner' - billing_contacts = fields.Many2many(string='Default Billing Contacts', - comodel_name='res.partner', - compute='_compute_billing_contacts', - inverse='_inverse_billing_contacts') - potential_billing_contacts = fields.Many2many(comodel_name='res.partner', - compute='_compute_billing_contacts') + billing_contacts = fields.Many2many( + string='Default Billing Contacts', + comodel_name='res.partner', + compute='_compute_billing_contacts', + inverse='_inverse_billing_contacts' + ) + + potential_billing_contacts = fields.Many2many( + comodel_name='res.partner', + compute='_compute_billing_contacts' + ) @api.depends('child_ids.type') def _compute_billing_contacts(self): diff --git a/bemade_multiple_billing_contacts/models/sale_order.py b/bemade_multiple_billing_contacts/models/sale_order.py index 877cc5d..ee6b75a 100644 --- a/bemade_multiple_billing_contacts/models/sale_order.py +++ b/bemade_multiple_billing_contacts/models/sale_order.py @@ -4,11 +4,13 @@ from odoo import models, fields, api, _, Command class SaleOrder(models.Model): _inherit = 'sale.order' - billing_contacts = fields.Many2many(comodel_name='res.partner', - string='Billing Contacts', - compute='_compute_billing_contacts', - inverse='_inverse_billing_contacts', - store=True) + billing_contacts = fields.Many2many( + comodel_name='res.partner', + string='Billing Contacts', + compute='_compute_billing_contacts', + inverse='_inverse_billing_contacts', + store=True + ) @api.depends('partner_id') def _compute_billing_contacts(self): diff --git a/bemade_partner_email_domain/data/mail_template_data.xml b/bemade_partner_email_domain/data/mail_template_data.xml index 4ff77c6..aeff016 100644 --- a/bemade_partner_email_domain/data/mail_template_data.xml +++ b/bemade_partner_email_domain/data/mail_template_data.xml @@ -8,13 +8,13 @@ {{object.id}} Select Your Division at {{object.company_id.name}} - +
- +
@@ -25,8 +25,8 @@
- +
@@ -55,8 +55,8 @@
- +
@@ -104,4 +104,3 @@ - diff --git a/bemade_partner_email_domain/data/template_data.xml b/bemade_partner_email_domain/data/template_data.xml index 471491e..ee3d6e7 100644 --- a/bemade_partner_email_domain/data/template_data.xml +++ b/bemade_partner_email_domain/data/template_data.xml @@ -14,4 +14,4 @@ - \ No newline at end of file +