'decimal:2', 'sale_price' => 'decimal:2', 'markup_used' => 'decimal:4', 'contribution_margin' => 'decimal:2', 'is_active' => 'boolean', ]; /** * Relacionamento com usuário */ public function user(): BelongsTo { return $this->belongsTo(User::class); } /** * Relacionamento com configuração de negócio */ public function businessSetting(): BelongsTo { return $this->belongsTo(BusinessSetting::class); } /** * Itens/componentes de custo desta ficha técnica */ public function items(): HasMany { return $this->hasMany(ProductSheetItem::class)->orderBy('sort_order'); } /** * Recalcula o CMV total baseado nos itens * * @return float */ public function recalculateCmv(): float { $this->cmv_total = $this->items()->sum('unit_cost'); $this->save(); return $this->cmv_total; } /** * Calcula e atualiza o preço de venda usando o Markup da configuração * * @param BusinessSetting|null $businessSetting * @return float */ public function calculateSalePrice(?BusinessSetting $businessSetting = null): float { $setting = $businessSetting ?? $this->businessSetting; if (!$setting) { return 0; } $markup = $setting->markup_factor ?? $setting->calculateMarkup(); if ($markup <= 0) { return 0; } $this->markup_used = $markup; $this->sale_price = round($this->cmv_total * $markup, 2); $this->contribution_margin = $this->sale_price - $this->cmv_total; $this->save(); return $this->sale_price; } /** * Retorna a margem de contribuição percentual * * @return float */ public function getContributionMarginPercentAttribute(): float { if ($this->sale_price <= 0) { return 0; } return round(($this->contribution_margin / $this->sale_price) * 100, 2); } /** * Scope para buscar fichas do usuário */ public function scopeOfUser($query, $userId) { return $query->where('user_id', $userId); } /** * Scope para buscar apenas fichas ativas */ public function scopeActive($query) { return $query->where('is_active', true); } /** * Scope para buscar por categoria */ public function scopeByCategory($query, $category) { return $query->where('category', $category); } }