webmoney/backend/app/Http/Controllers/Api/BusinessSettingController.php
CnxiFly Dev 84d9d7d187 feat(business): add Business section with Markup pricing v1.28.0
- Add business_settings table for Markup configuration
- Add product_sheets table for product technical sheets (CMV)
- Add product_sheet_items table for cost components
- Create BusinessSetting model with calculateMarkup() method
- Create ProductSheet model with recalculateCmv() method
- Create ProductSheetItem model for cost breakdown
- Add BusinessSettingController with CRUD + simulate-price endpoint
- Add ProductSheetController with CRUD + items management + duplicate
- Add Business page with 3 tabs (Settings, Products, Calculator)
- Add BusinessSettingsTab component with markup cards
- Add ProductSheetsTab component with product grid
- Add PriceCalculatorTab component with interactive simulator
- Add i18n translations in ES, PT-BR, EN
- Multi-currency support (EUR, BRL, USD)
2025-12-14 07:44:18 +01:00

216 lines
7.4 KiB
PHP

<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\BusinessSetting;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class BusinessSettingController extends Controller
{
/**
* Lista todas as configurações de negócio do usuário
*/
public function index(Request $request): JsonResponse
{
$userId = $request->user()->id;
$settings = BusinessSetting::ofUser($userId)
->orderBy('is_active', 'desc')
->orderBy('name')
->get()
->map(function ($setting) {
return array_merge($setting->toArray(), [
'fixed_expenses_rate' => $setting->fixed_expenses_rate,
'total_variable_costs' => $setting->total_variable_costs,
'markup_breakdown' => $setting->markup_breakdown,
]);
});
return response()->json($settings);
}
/**
* Cria uma nova configuração de negócio
*/
public function store(Request $request): JsonResponse
{
$validator = Validator::make($request->all(), [
'name' => 'required|string|max:255',
'currency' => 'required|string|size:3',
'monthly_revenue' => 'required|numeric|min:0',
'fixed_expenses' => 'required|numeric|min:0',
'tax_rate' => 'required|numeric|min:0|max:100',
'sales_commission' => 'required|numeric|min:0|max:100',
'card_fee' => 'required|numeric|min:0|max:100',
'other_variable_costs' => 'nullable|numeric|min:0|max:100',
'investment_rate' => 'required|numeric|min:0|max:100',
'profit_margin' => 'required|numeric|min:0|max:100',
]);
if ($validator->fails()) {
return response()->json(['errors' => $validator->errors()], 422);
}
$data = $validator->validated();
$data['user_id'] = $request->user()->id;
$data['other_variable_costs'] = $data['other_variable_costs'] ?? 0;
$setting = BusinessSetting::create($data);
// Calcular e salvar o markup
$setting->recalculateMarkup();
// Recarregar com os dados calculados
$setting->refresh();
return response()->json(array_merge($setting->toArray(), [
'fixed_expenses_rate' => $setting->fixed_expenses_rate,
'total_variable_costs' => $setting->total_variable_costs,
'markup_breakdown' => $setting->markup_breakdown,
]), 201);
}
/**
* Exibe uma configuração específica
*/
public function show(Request $request, $id): JsonResponse
{
$setting = BusinessSetting::ofUser($request->user()->id)
->with('productSheets')
->findOrFail($id);
return response()->json(array_merge($setting->toArray(), [
'fixed_expenses_rate' => $setting->fixed_expenses_rate,
'total_variable_costs' => $setting->total_variable_costs,
'markup_breakdown' => $setting->markup_breakdown,
]));
}
/**
* Atualiza uma configuração
*/
public function update(Request $request, $id): JsonResponse
{
$setting = BusinessSetting::ofUser($request->user()->id)->findOrFail($id);
$validator = Validator::make($request->all(), [
'name' => 'sometimes|string|max:255',
'currency' => 'sometimes|string|size:3',
'monthly_revenue' => 'sometimes|numeric|min:0',
'fixed_expenses' => 'sometimes|numeric|min:0',
'tax_rate' => 'sometimes|numeric|min:0|max:100',
'sales_commission' => 'sometimes|numeric|min:0|max:100',
'card_fee' => 'sometimes|numeric|min:0|max:100',
'other_variable_costs' => 'sometimes|numeric|min:0|max:100',
'investment_rate' => 'sometimes|numeric|min:0|max:100',
'profit_margin' => 'sometimes|numeric|min:0|max:100',
'is_active' => 'sometimes|boolean',
]);
if ($validator->fails()) {
return response()->json(['errors' => $validator->errors()], 422);
}
$setting->update($validator->validated());
// Recalcular markup
$setting->recalculateMarkup();
$setting->refresh();
return response()->json(array_merge($setting->toArray(), [
'fixed_expenses_rate' => $setting->fixed_expenses_rate,
'total_variable_costs' => $setting->total_variable_costs,
'markup_breakdown' => $setting->markup_breakdown,
]));
}
/**
* Remove uma configuração
*/
public function destroy(Request $request, $id): JsonResponse
{
$setting = BusinessSetting::ofUser($request->user()->id)->findOrFail($id);
// Verificar se há fichas técnicas vinculadas
if ($setting->productSheets()->count() > 0) {
return response()->json([
'message' => 'Não é possível excluir: existem fichas técnicas vinculadas a esta configuração.'
], 422);
}
$setting->delete();
return response()->json(['message' => 'Configuração excluída com sucesso']);
}
/**
* Recalcula o markup de uma configuração
*/
public function recalculateMarkup(Request $request, $id): JsonResponse
{
$setting = BusinessSetting::ofUser($request->user()->id)->findOrFail($id);
$markup = $setting->recalculateMarkup();
return response()->json([
'markup_factor' => $markup,
'markup_breakdown' => $setting->markup_breakdown,
]);
}
/**
* Simula um preço de venda dado um CMV
*/
public function simulatePrice(Request $request, $id): JsonResponse
{
$setting = BusinessSetting::ofUser($request->user()->id)->findOrFail($id);
$validator = Validator::make($request->all(), [
'cmv' => 'required|numeric|min:0',
]);
if ($validator->fails()) {
return response()->json(['errors' => $validator->errors()], 422);
}
$cmv = $request->cmv;
$salePrice = $setting->calculateSalePrice($cmv);
$contributionMargin = $salePrice - $cmv;
$contributionMarginPercent = $salePrice > 0 ? round(($contributionMargin / $salePrice) * 100, 2) : 0;
return response()->json([
'cmv' => $cmv,
'markup_factor' => $setting->markup_factor,
'sale_price' => $salePrice,
'contribution_margin' => $contributionMargin,
'contribution_margin_percent' => $contributionMarginPercent,
'currency' => $setting->currency,
'breakdown' => $setting->markup_breakdown,
]);
}
/**
* Retorna a configuração ativa padrão do usuário
*/
public function getDefault(Request $request): JsonResponse
{
$setting = BusinessSetting::ofUser($request->user()->id)
->active()
->first();
if (!$setting) {
return response()->json(['message' => 'Nenhuma configuração ativa encontrada'], 404);
}
return response()->json(array_merge($setting->toArray(), [
'fixed_expenses_rate' => $setting->fixed_expenses_rate,
'total_variable_costs' => $setting->total_variable_costs,
'markup_breakdown' => $setting->markup_breakdown,
]));
}
}