Deep dive: Account, Stock, Sale, Purchase — +800 LOC business logic
Account: - Multi-currency: company_currency_id, amount_total_signed - Lock dates on res.company (period, fiscal year, tax) + enforcement in action_post - Recurring entries: account.move.recurring with action_generate (copy+advance) - Tax groups: amount_type='group' computes child taxes with include_base_amount - ComputeTaxes batch function, findTaxAccount helper Stock: - Lot/Serial tracking: enhanced stock.lot with expiration dates + qty compute - Routes: stock.route model with product/category/warehouse selectable flags - Rules: stock.rule model with pull/push/buy/manufacture actions + procure methods - Returns: action_return on picking (swap locations, copy moves) - Product tracking extension (none/lot/serial) + route_ids M2M Sale: - Pricelist: get_product_price with fixed/percentage/formula computation - Margin: purchase_price, margin, margin_percent on line + order totals - Down payments: action_create_down_payment (deposit invoice at X%) Purchase: - 3-way matching: action_create_bill now updates qty_invoiced on PO lines - Purchase agreements: purchase.requisition + line with state machine Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
68
addons/sale/models/sale_margin.go
Normal file
68
addons/sale/models/sale_margin.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package models
|
||||
|
||||
import "odoo-go/pkg/orm"
|
||||
|
||||
// initSaleMargin adds margin fields to sale.order.line and sale.order.
|
||||
// Mirrors: odoo/addons/sale_margin/models/sale_order_line.py + sale_order.py
|
||||
|
||||
func initSaleMargin() {
|
||||
// -- Extend sale.order.line with margin fields --
|
||||
line := orm.ExtendModel("sale.order.line")
|
||||
line.AddFields(
|
||||
orm.Float("purchase_price", orm.FieldOpts{String: "Cost Price"}),
|
||||
orm.Monetary("margin", orm.FieldOpts{
|
||||
String: "Margin", Compute: "_compute_margin", Store: true, CurrencyField: "currency_id",
|
||||
}),
|
||||
orm.Float("margin_percent", orm.FieldOpts{
|
||||
String: "Margin (%)", Compute: "_compute_margin", Store: true,
|
||||
}),
|
||||
)
|
||||
|
||||
computeLineMargin := func(rs *orm.Recordset) (orm.Values, error) {
|
||||
env := rs.Env()
|
||||
lineID := rs.IDs()[0]
|
||||
var subtotal, cost float64
|
||||
env.Tx().QueryRow(env.Ctx(),
|
||||
`SELECT COALESCE(price_subtotal, 0), COALESCE(purchase_price, 0) * COALESCE(product_uom_qty, 0)
|
||||
FROM sale_order_line WHERE id = $1`, lineID,
|
||||
).Scan(&subtotal, &cost)
|
||||
margin := subtotal - cost
|
||||
pct := float64(0)
|
||||
if subtotal > 0 {
|
||||
pct = margin / subtotal * 100
|
||||
}
|
||||
return orm.Values{"margin": margin, "margin_percent": pct}, nil
|
||||
}
|
||||
line.RegisterCompute("margin", computeLineMargin)
|
||||
line.RegisterCompute("margin_percent", computeLineMargin)
|
||||
|
||||
// -- Extend sale.order with total margin --
|
||||
so := orm.ExtendModel("sale.order")
|
||||
so.AddFields(
|
||||
orm.Monetary("margin", orm.FieldOpts{
|
||||
String: "Margin", Compute: "_compute_margin", Store: true, CurrencyField: "currency_id",
|
||||
}),
|
||||
orm.Float("margin_percent", orm.FieldOpts{
|
||||
String: "Margin (%)", Compute: "_compute_margin", Store: true,
|
||||
}),
|
||||
)
|
||||
|
||||
computeSOMargin := func(rs *orm.Recordset) (orm.Values, error) {
|
||||
env := rs.Env()
|
||||
soID := rs.IDs()[0]
|
||||
var margin, untaxed float64
|
||||
env.Tx().QueryRow(env.Ctx(),
|
||||
`SELECT COALESCE(SUM(margin), 0), COALESCE(SUM(price_subtotal), 0)
|
||||
FROM sale_order_line WHERE order_id = $1
|
||||
AND (display_type IS NULL OR display_type = '' OR display_type = 'product')`,
|
||||
soID,
|
||||
).Scan(&margin, &untaxed)
|
||||
pct := float64(0)
|
||||
if untaxed > 0 {
|
||||
pct = margin / untaxed * 100
|
||||
}
|
||||
return orm.Values{"margin": margin, "margin_percent": pct}, nil
|
||||
}
|
||||
so.RegisterCompute("margin", computeSOMargin)
|
||||
so.RegisterCompute("margin_percent", computeSOMargin)
|
||||
}
|
||||
Reference in New Issue
Block a user