113 lines
4.2 KiB
Python
113 lines
4.2 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Copyright 2026 Nexa Systems Inc.
|
|
# License OPL-1 (Odoo Proprietary License v1.0)
|
|
|
|
from odoo import models, fields, api
|
|
|
|
|
|
class ResConfigSettings(models.TransientModel):
|
|
_inherit = 'res.config.settings'
|
|
|
|
fi_case_conversion = fields.Selection([
|
|
('none', 'No Conversion'),
|
|
('upper', 'UPPERCASE'),
|
|
('sentence', 'Sentence case'),
|
|
('capitalized', 'Capitalized Case'),
|
|
('lower', 'lowercase'),
|
|
], string='Product Name Case',
|
|
config_parameter='fusion_inventory.case_conversion',
|
|
default='none',
|
|
help='Globally convert all product names to the selected case. '
|
|
'Overrides individual product settings and applies to new products.')
|
|
|
|
fi_auto_update_cost = fields.Boolean(
|
|
string='Auto-Update Cost from Vendor Bills',
|
|
config_parameter='fusion_inventory.auto_update_cost',
|
|
default=True,
|
|
help='Automatically update product cost when a vendor bill is confirmed. '
|
|
'Uses the latest bill line price (skips zero-price lines).')
|
|
|
|
fi_default_margin = fields.Float(
|
|
string='Default Margin (%)',
|
|
config_parameter='fusion_inventory.default_margin',
|
|
default=0,
|
|
help='Default margin percentage applied to new products.')
|
|
|
|
fi_booking_hold_hours = fields.Integer(
|
|
string='Booking Hold Duration (hours)',
|
|
config_parameter='fusion_inventory.booking_hold_hours',
|
|
default=24,
|
|
help='How many hours a product booking holds before auto-expiring.')
|
|
|
|
fi_openai_api_key = fields.Char(
|
|
string='OpenAI API Key',
|
|
config_parameter='fusion_inventory.openai_api_key',
|
|
help='API key for OpenAI features (discrepancy analysis, notes parsing). '
|
|
'Falls back to Fusion Digitize key if empty.')
|
|
|
|
@api.model
|
|
def get_fi_openai_key(self):
|
|
"""Return the effective OpenAI API key, falling back to Fusion Digitize."""
|
|
key = self.env['ir.config_parameter'].sudo().get_param(
|
|
'fusion_inventory.openai_api_key', ''
|
|
)
|
|
if not key:
|
|
key = self.env['ir.config_parameter'].sudo().get_param(
|
|
'fusion_digitize.openai_api_key', ''
|
|
)
|
|
return key or ''
|
|
|
|
def action_sync_all_costs_from_bills(self):
|
|
"""Pull every product's cost from its latest posted vendor bill line."""
|
|
products = self.env['product.template'].sudo().search([])
|
|
products._sync_cost_from_latest_bill()
|
|
return {
|
|
'type': 'ir.actions.client',
|
|
'tag': 'display_notification',
|
|
'params': {
|
|
'title': 'Cost Sync Complete',
|
|
'message': f'Checked {len(products)} products against vendor bill history.',
|
|
'type': 'success',
|
|
'sticky': False,
|
|
},
|
|
}
|
|
|
|
def action_apply_case_conversion_all(self):
|
|
"""Apply the global case conversion to all existing products."""
|
|
mode = self.fi_case_conversion
|
|
if not mode or mode == 'none':
|
|
return {
|
|
'type': 'ir.actions.client',
|
|
'tag': 'display_notification',
|
|
'params': {
|
|
'title': 'No Conversion Selected',
|
|
'message': 'Select a case conversion option first.',
|
|
'type': 'warning',
|
|
'sticky': False,
|
|
},
|
|
}
|
|
|
|
products = self.env['product.template'].search([])
|
|
count = 0
|
|
for product in products:
|
|
converted = self.env['product.template']._apply_case_conversion(
|
|
product.name, mode
|
|
)
|
|
if converted and converted != product.name:
|
|
product.with_context(_fi_converting_case=True).write({
|
|
'name': converted,
|
|
'x_fi_case_conversion': mode,
|
|
})
|
|
count += 1
|
|
|
|
return {
|
|
'type': 'ir.actions.client',
|
|
'tag': 'display_notification',
|
|
'params': {
|
|
'title': 'Case Conversion Applied',
|
|
'message': f'{count} product names converted to {mode}.',
|
|
'type': 'success',
|
|
'sticky': False,
|
|
},
|
|
}
|