package models import ( "database/sql/driver" "encoding/json" "errors" "time" ) type ConfigItem struct { LotName string `json:"lot_name"` Quantity int `json:"quantity"` UnitPrice float64 `json:"unit_price"` } type ConfigItems []ConfigItem func (c ConfigItems) Value() (driver.Value, error) { return json.Marshal(c) } func (c *ConfigItems) Scan(value interface{}) error { if value == nil { *c = make(ConfigItems, 0) return nil } bytes, ok := value.([]byte) if !ok { return errors.New("type assertion to []byte failed") } return json.Unmarshal(bytes, c) } func (c ConfigItems) Total() float64 { var total float64 for _, item := range c { total += item.UnitPrice * float64(item.Quantity) } return total } type VendorSpecLotAllocation struct { LotName string `json:"lot_name"` Quantity int `json:"quantity"` } type VendorSpecLotMapping struct { LotName string `json:"lot_name"` QuantityPerPN int `json:"quantity_per_pn"` } type VendorSpecItem struct { SortOrder int `json:"sort_order"` VendorPartnumber string `json:"vendor_partnumber"` Quantity int `json:"quantity"` Description string `json:"description,omitempty"` UnitPrice *float64 `json:"unit_price,omitempty"` TotalPrice *float64 `json:"total_price,omitempty"` ResolvedLotName string `json:"resolved_lot_name,omitempty"` ResolutionSource string `json:"resolution_source,omitempty"` ManualLotSuggestion string `json:"manual_lot_suggestion,omitempty"` LotQtyPerPN int `json:"lot_qty_per_pn,omitempty"` LotAllocations []VendorSpecLotAllocation `json:"lot_allocations,omitempty"` LotMappings []VendorSpecLotMapping `json:"lot_mappings,omitempty"` } type VendorSpec []VendorSpecItem func (v VendorSpec) Value() (driver.Value, error) { if v == nil { return nil, nil } return json.Marshal(v) } func (v *VendorSpec) Scan(value interface{}) error { if value == nil { *v = nil return nil } var bytes []byte switch val := value.(type) { case []byte: bytes = val case string: bytes = []byte(val) default: return errors.New("type assertion failed for VendorSpec") } return json.Unmarshal(bytes, v) } type Configuration struct { ID uint `gorm:"primaryKey;autoIncrement" json:"id"` UUID string `gorm:"size:36;uniqueIndex;not null" json:"uuid"` UserID *uint `json:"user_id,omitempty"` // Legacy field, no longer required for ownership OwnerUsername string `gorm:"size:100;not null;default:'';index" json:"owner_username"` ProjectUUID *string `gorm:"size:36;index" json:"project_uuid,omitempty"` AppVersion string `gorm:"size:64" json:"app_version,omitempty"` Name string `gorm:"size:200;not null" json:"name"` Items ConfigItems `gorm:"type:json;not null" json:"items"` TotalPrice *float64 `gorm:"type:decimal(12,2)" json:"total_price"` CustomPrice *float64 `gorm:"type:decimal(12,2)" json:"custom_price"` Notes string `gorm:"type:text" json:"notes"` IsTemplate bool `gorm:"default:false" json:"is_template"` ServerCount int `gorm:"default:1" json:"server_count"` ServerModel string `gorm:"size:100" json:"server_model,omitempty"` SupportCode string `gorm:"size:20" json:"support_code,omitempty"` Article string `gorm:"size:80" json:"article,omitempty"` PricelistID *uint `gorm:"index" json:"pricelist_id,omitempty"` WarehousePricelistID *uint `gorm:"index" json:"warehouse_pricelist_id,omitempty"` CompetitorPricelistID *uint `gorm:"index" json:"competitor_pricelist_id,omitempty"` VendorSpec VendorSpec `gorm:"type:json" json:"vendor_spec,omitempty"` DisablePriceRefresh bool `gorm:"default:false" json:"disable_price_refresh"` OnlyInStock bool `gorm:"default:false" json:"only_in_stock"` Line int `gorm:"column:line_no;index" json:"line"` PriceUpdatedAt *time.Time `gorm:"type:timestamp" json:"price_updated_at,omitempty"` CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"` CurrentVersionNo int `gorm:"-" json:"current_version_no,omitempty"` } func (Configuration) TableName() string { return "qt_configurations" } type PriceOverride struct { ID uint `gorm:"primaryKey;autoIncrement" json:"id"` LotName string `gorm:"size:255;not null" json:"lot_name"` Price float64 `gorm:"type:decimal(12,2);not null" json:"price"` ValidFrom time.Time `gorm:"type:date;not null" json:"valid_from"` ValidUntil *time.Time `gorm:"type:date" json:"valid_until"` Reason string `gorm:"type:text" json:"reason"` CreatedBy uint `gorm:"not null" json:"created_by"` } func (PriceOverride) TableName() string { return "qt_price_overrides" }