store-manage/app/Http/Controllers/Api/LedgerController.php

236 lines
8.3 KiB
PHP

<?php
namespace App\Http\Controllers\Api;
use App\Enums\TaskStatus;
use App\Exceptions\RuntimeException;
use App\Http\Controllers\Api\Controller;
use App\Models\Keyword;
use App\Models\Ledger;
use App\Models\LedgerItem;
use App\Models\TaskLedger;
use App\Models\TaskPerformance;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Throwable;
class LedgerController extends Controller
{
public function store(Request $request)
{
/** @var \App\Models\Employee */
$user = $request->user();
if (! $user->isStoreMaster()) {
throw new RuntimeException('非店长不可上报数据');
}
// 是否是彩票店数据上报
$isLotteryLedger = $user->store->isLotteryStore();
$validated = $request->validate(
rules: [
'date' => ['bail', 'required', 'date_format:Y-m-d'],
'items' => $isLotteryLedger ? ['bail', 'required', 'array'] : ['bail', 'array'],
'new_customers' => ['bail', 'required', 'int', 'min:0'],
'sales' => ['bail', 'required', 'numeric', 'min:0'],
'expenditure' => ['bail', 'required', 'numeric', 'min:0'],
'handover_amount' => ['bail', 'required', 'numeric', 'min:0'],
'photos' => ['bail', 'required', 'array'],
],
attributes: [
'date' => '日期',
'items' => '彩种数据',
'new_customers' => '新增客户',
'sales' => '销售合计',
'expenditure' => $isLotteryLedger ? '兑奖合计' : '支出合计',
'handover_amount' => '交账金额',
'photos' => '时段报表照片',
],
);
/** @var \Illuminate\Database\Eloquent\Collection */
$lotteryTypes = Keyword::filter(['parent_key' => 'lottery_type'])
->oldest('sort')
->get();
// 上报数据项的格式:
// [
// ['id' => '上报数据类型1', 'sales' => '销售金额', 'expenditure' => '兑奖金额'],
// ['id' => '上报数据类型2', 'sales' => '销售金额', 'expenditure' => '兑奖金额'],
// ]
if ($isLotteryLedger) {
$items = collect($validated['items'])->keyBy('id');
/** @var \App\Models\Keyword */
foreach ($lotteryTypes as $lotteryType) {
$item = $items->get($lotteryType->key);
if (is_null($item)) {
throw new RuntimeException("{$lotteryType->name}未填写上报数据");
}
Validator::validate(
data: $item,
rules: [
'sales' => ['bail', 'required', 'numeric', 'min:0'],
'expenditure' => ['bail', 'required', 'numeric', 'min:0'],
],
attributes: [
'sales' => "[$lotteryType->name]销售金额",
'expenditure' => "[$lotteryType->name]兑奖金额",
],
);
}
}
$date = Carbon::createFromFormat('Y-m-d', $validated['date']);
/** @var \App\Models\Ledger|null */
$ledger = Ledger::where('store_id', $user->store_id)
->where('date', $date->format('Y-m-d'))
->first();
if ($ledger && ! $ledger->allowReReport()) {
throw new RuntimeException('上报数据已更新,不可重新上传');
}
$ratio = bcdiv($user->store->profit_ratio, 100, 4);
// 计算预期佣金
$validated['expected_commission'] = bcmul($validated['sales'], $ratio, 2);
// 计算预期收益
$validated['expected_income'] = bcsub($validated['expected_commission'], $validated['expenditure'], 2);
try {
DB::beginTransaction();
if (is_null($ledger)) {
$ledger = Ledger::create(
array_merge($validated, ['store_id' => $user->store_id])
);
} else {
$ledger->update($validated);
$ledger->items()->delete();
}
LedgerItem::insert(
collect(
$isLotteryLedger ? $validated['items'] : [
[
'id' => 'ledger_item_type_other',
'sales' => $ledger->sales,
'expenditure' => $ledger->expenditure,
],
]
)->map(fn ($item) => [
'date' => $ledger->date,
'store_id' => $ledger->store_id,
'ledger_id' => $ledger->id,
'ledger_item_type_id' => $item['id'],
'sales' => $item['sales'],
'expenditure' => $item['expenditure'],
'created_at' => $ledger->updated_at,
'updated_at' => $ledger->updated_at,
])->all()
);
// 总账录入任务
/** @var \App\Models\TaskLedger */
$taskLedger = TaskLedger::where('store_id', $user->store_id)
->where('date', $ledger->date)
->first();
if ($taskLedger) {
/** @var \App\Models\Task */
$task = $taskLedger->task;
if (! $task->isSuccess()) {
$task->markAsSuccess();
}
}
// 业绩指标任务
/** @var \App\Models\TaskPerformance */
$taskPerformance = TaskPerformance::where('store_id', $ledger->store_id)
->where('month', $date->format('Y-m'))
->first();
if ($taskPerformance) {
$actualPerformance = Ledger::where('store_id', $ledger->store_id)
->whereBetween('date', [$date->copy()->startOfMonth()->format('Y-m-d'), $date->copy()->endOfMonth()->format('Y-m-d')])
->sum('sales');
$taskPerformance->update([
'actual_performance' => $actualPerformance,
]);
if ($taskPerformance->isSuccess()) {
/** @var \App\Models\Task */
$task = $taskPerformance->task;
if (! $task->isSuccess()) {
$task->markAsSuccess();
}
}
}
DB::commit();
} catch (Throwable $e) {
DB::rollBack();
throw tap($e, fn ($e) => report($e));
}
return response()->noContent();
}
public function show(string $date, Request $request)
{
/** @var \App\Models\Employee */
$user = $request->user();
/** @var \App\Models\Ledger|null */
$ledger = Ledger::with(['items'])
->where('store_id', $user->store_id)
->where('date', $date)
->first();
$items = [];
if ($user->store->isLotteryStore()) {
/** @var \Illuminate\Database\Eloquent\Collection */
$lotteryTypes = Keyword::filter(['parent_key' => 'lottery_type'])
->oldest('sort')
->get();
$ledgerItems = collect();
if ($ledger) {
$ledgerItems = $ledger->items->keyBy('ledger_item_type_id');
}
$items = $lotteryTypes->map(function ($lotteryType) use ($ledgerItems) {
$ledgerItem = $ledgerItems->get($lotteryType->key);
return [
'id' => $lotteryType->key,
'name' => $lotteryType->name,
'sales' => $ledgerItem?->sales,
'expenditure' => $ledgerItem?->expenditure,
];
})->all();
}
return [
'date' => $date,
'items' => $items,
'new_customers' => $ledger?->new_customers,
'sales' => $ledger?->sales,
'expenditure' => $ledger?->expenditure,
'handover_amount' => $ledger?->handover_amount,
'photos' => $ledger?->photos ?: [],
'allow_rereport' => is_null($ledger) ? true : $ledger->allowReReport(),
];
}
}