- 基础环境:Docker 部署配置,源码挂载实时同步 - 修复:super_admin 权限补全、登录重定向循环 - 开发:店铺营销账户账单 - 抖音账户(15字段汇总账单) - 开发:店铺营销账户账单 - 淘系支付宝账户(8字段流水账单) - 开发:店铺营销账户账单 - 拼多多账户(7字段流水账单) - 业务页面导航集成:config/business_navigation.php + Business\Pages 控制器 - 各平台独立表结构和视图,互不影响
314 lines
10 KiB
PHP
314 lines
10 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Banking;
|
|
|
|
use App\Abstracts\Http\Controller;
|
|
use App\Http\Requests\Banking\MarketingAccountBill as Request;
|
|
use App\Models\Banking\MarketingAccountBill;
|
|
use Illuminate\Http\RedirectResponse;
|
|
use Illuminate\Http\Request as HttpRequest;
|
|
|
|
class MarketingAccountBills extends Controller
|
|
{
|
|
/**
|
|
* 支持的营销账户平台列表
|
|
*/
|
|
public const PLATFORMS = [
|
|
'douyin' => 'platform_douyin',
|
|
'taobao-alipay' => 'platform_taobao-alipay',
|
|
'taobao-wechat' => 'platform_taobao-wechat',
|
|
'pinduoduo' => 'platform_pinduoduo',
|
|
'jd-wallet' => 'platform_jd-wallet',
|
|
'dewu' => 'platform_dewu',
|
|
'vipshop' => 'platform_vipshop',
|
|
];
|
|
|
|
public function __construct()
|
|
{
|
|
$this->middleware('permission:read-banking-accounts')->only('storeIndex', 'platformIndex');
|
|
$this->middleware('permission:create-banking-accounts')->only('create', 'store', 'import', 'template');
|
|
$this->middleware('permission:update-banking-accounts')->only('edit', 'update', 'export');
|
|
$this->middleware('permission:delete-banking-accounts')->only('destroy');
|
|
}
|
|
|
|
/**
|
|
* 平台选择页
|
|
*/
|
|
public function storeIndex()
|
|
{
|
|
return view('banking.marketing_account_bills.store-index', [
|
|
'platforms' => self::PLATFORMS,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 单平台账单列表
|
|
*/
|
|
public function platformIndex(string $platform)
|
|
{
|
|
return $this->index($platform);
|
|
}
|
|
|
|
/**
|
|
* 创建表单
|
|
*/
|
|
public function create(string $platform)
|
|
{
|
|
$platform = $this->resolvePlatform($platform);
|
|
|
|
return view('banking.marketing_account_bills.form', [
|
|
'platform' => $platform,
|
|
'account' => new MarketingAccountBill([
|
|
'company_id' => company_id(),
|
|
'bill_date' => now()->toDateString(),
|
|
]),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 下载导入模板
|
|
*/
|
|
public function template(string $platform)
|
|
{
|
|
$this->resolvePlatform($platform);
|
|
|
|
return response()->streamDownload(function () {
|
|
$csv = fopen('php://output', 'w');
|
|
fputs($csv, chr(0xEF) . chr(0xBB) . chr(0xBF)); // BOM for Excel
|
|
|
|
fputcsv($csv, [
|
|
'店铺名称', '账单日期', '总存入金额', '总转入金额', '总转出金额',
|
|
'非赠款消耗金额', '赠款消耗金额', '消返红包消耗金额', '立减红包消耗金额',
|
|
'共享钱包消耗金额', '共享赠款消耗金额', '当日资金总金额', '期末总余额',
|
|
'赠款余额', '非赠款余额', '备注',
|
|
]);
|
|
|
|
fclose($csv);
|
|
}, "marketing_account_bills_{$platform}_template.csv", [
|
|
'Content-Type' => 'text/csv; charset=UTF-8',
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 批量导出
|
|
*/
|
|
public function export(HttpRequest $request, string $platform)
|
|
{
|
|
$this->resolvePlatform($platform);
|
|
|
|
$ids = $request->validate([
|
|
'ids' => ['nullable', 'array', 'max:5000'],
|
|
'ids.*' => ['integer'],
|
|
])['ids'] ?? [];
|
|
|
|
$query = MarketingAccountBill::platform($platform)->oldest('id');
|
|
|
|
if (!empty($ids)) {
|
|
$query->whereKey($ids);
|
|
}
|
|
|
|
$bills = $query->get();
|
|
|
|
return response()->streamDownload(function () use ($bills) {
|
|
$csv = fopen('php://output', 'w');
|
|
fputs($csv, chr(0xEF) . chr(0xBB) . chr(0xBF));
|
|
|
|
fputcsv($csv, [
|
|
'店铺名称', '账单日期', '总存入金额', '总转入金额', '总转出金额',
|
|
'非赠款消耗金额', '赠款消耗金额', '消返红包消耗金额', '立减红包消耗金额',
|
|
'共享钱包消耗金额', '共享赠款消耗金额', '当日资金总金额', '期末总余额',
|
|
'赠款余额', '非赠款余额', '备注',
|
|
]);
|
|
|
|
foreach ($bills as $bill) {
|
|
fputcsv($csv, [
|
|
$bill->store_name,
|
|
$bill->bill_date->toDateString(),
|
|
$bill->total_deposit,
|
|
$bill->total_transfer_in,
|
|
$bill->total_transfer_out,
|
|
$bill->non_grant_consumption,
|
|
$bill->grant_consumption,
|
|
$bill->rebate_redpack_consumption,
|
|
$bill->discount_redpack_consumption,
|
|
$bill->shared_wallet_consumption,
|
|
$bill->shared_grant_consumption,
|
|
$bill->daily_total_amount,
|
|
$bill->period_end_balance,
|
|
$bill->grant_balance,
|
|
$bill->non_grant_balance,
|
|
$bill->notes,
|
|
]);
|
|
}
|
|
|
|
fclose($csv);
|
|
}, 'marketing_account_bills_export.csv', [
|
|
'Content-Type' => 'text/csv; charset=UTF-8',
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 批量导入
|
|
*/
|
|
public function import(HttpRequest $request, string $platform): RedirectResponse
|
|
{
|
|
$this->resolvePlatform($platform);
|
|
|
|
$validated = $request->validate([
|
|
'import' => ['required', 'file', 'mimes:xlsx,xls,csv', 'max:5120'],
|
|
], [
|
|
'import.required' => trans('marketing_account_bills.import_required'),
|
|
'import.mimes' => trans('marketing_account_bills.import_file_type'),
|
|
'import.max' => trans('marketing_account_bills.import_file_size'),
|
|
]);
|
|
|
|
$file = $validated['import'];
|
|
$handle = fopen($file->getRealPath(), 'r');
|
|
|
|
// Skip BOM
|
|
$bom = fread($handle, 3);
|
|
if ($bom !== chr(0xEF) . chr(0xBB) . chr(0xBF)) {
|
|
rewind($handle);
|
|
}
|
|
|
|
// Skip header
|
|
fgetcsv($handle);
|
|
|
|
$count = 0;
|
|
$companyId = company_id();
|
|
$userId = user()->id;
|
|
|
|
while (($row = fgetcsv($handle)) !== false) {
|
|
if (empty($row[0]) && empty($row[1])) {
|
|
continue;
|
|
}
|
|
|
|
MarketingAccountBill::create([
|
|
'company_id' => $companyId,
|
|
'platform' => $platform,
|
|
'store_name' => $row[0] ?? '',
|
|
'bill_date' => $row[1] ?? now()->toDateString(),
|
|
'total_deposit' => (float) ($row[2] ?? 0),
|
|
'total_transfer_in' => (float) ($row[3] ?? 0),
|
|
'total_transfer_out' => (float) ($row[4] ?? 0),
|
|
'non_grant_consumption' => (float) ($row[5] ?? 0),
|
|
'grant_consumption' => (float) ($row[6] ?? 0),
|
|
'rebate_redpack_consumption' => (float) ($row[7] ?? 0),
|
|
'discount_redpack_consumption' => (float) ($row[8] ?? 0),
|
|
'shared_wallet_consumption' => (float) ($row[9] ?? 0),
|
|
'shared_grant_consumption' => (float) ($row[10] ?? 0),
|
|
'daily_total_amount' => (float) ($row[11] ?? 0),
|
|
'period_end_balance' => (float) ($row[12] ?? 0),
|
|
'grant_balance' => (float) ($row[13] ?? 0),
|
|
'non_grant_balance' => (float) ($row[14] ?? 0),
|
|
'notes' => $row[15] ?? null,
|
|
'created_from' => 'core::ui',
|
|
'created_by' => $userId,
|
|
]);
|
|
|
|
$count++;
|
|
}
|
|
|
|
fclose($handle);
|
|
|
|
flash(trans('marketing_account_bills.import_success', ['count' => $count]))->success();
|
|
|
|
return redirect()->route('marketing-account-bills.platform.index', $platform);
|
|
}
|
|
|
|
/**
|
|
* 存储新账单
|
|
*/
|
|
public function store(Request $request, string $platform): RedirectResponse
|
|
{
|
|
$this->resolvePlatform($platform);
|
|
$data = $request->validated();
|
|
|
|
MarketingAccountBill::create(array_merge($data, [
|
|
'company_id' => company_id(),
|
|
'platform' => $platform,
|
|
'created_from' => 'core::ui',
|
|
'created_by' => user()->id,
|
|
]));
|
|
|
|
flash(trans('messages.success.created', ['type' => $this->platformTitle($platform)]))->success();
|
|
|
|
return redirect()->route('marketing-account-bills.platform.index', $platform);
|
|
}
|
|
|
|
/**
|
|
* 编辑表单
|
|
*/
|
|
public function edit(string $platform, MarketingAccountBill $marketingAccountBill)
|
|
{
|
|
abort_unless($marketingAccountBill->platform === $this->resolvePlatform($platform), 404);
|
|
|
|
return view('banking.marketing_account_bills.form', [
|
|
'platform' => $marketingAccountBill->platform,
|
|
'account' => $marketingAccountBill,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 更新账单
|
|
*/
|
|
public function update(Request $request, string $platform, MarketingAccountBill $marketingAccountBill): RedirectResponse
|
|
{
|
|
abort_unless($marketingAccountBill->platform === $this->resolvePlatform($platform), 404);
|
|
|
|
$marketingAccountBill->update($request->validated());
|
|
|
|
flash(trans('messages.success.updated', ['type' => $this->platformTitle($platform)]))->success();
|
|
|
|
return redirect()->route('marketing-account-bills.platform.index', $platform);
|
|
}
|
|
|
|
/**
|
|
* 删除账单
|
|
*/
|
|
public function destroy(string $platform, MarketingAccountBill $marketingAccountBill): RedirectResponse
|
|
{
|
|
abort_unless($marketingAccountBill->platform === $this->resolvePlatform($platform), 404);
|
|
|
|
$marketingAccountBill->delete();
|
|
|
|
flash(trans('messages.success.deleted', ['type' => $this->platformTitle($platform)]))->success();
|
|
|
|
return redirect()->route('marketing-account-bills.platform.index', $platform);
|
|
}
|
|
|
|
/**
|
|
* 列表页
|
|
*/
|
|
private function index(string $platform)
|
|
{
|
|
$platform = $this->resolvePlatform($platform);
|
|
|
|
return view('banking.marketing_account_bills.index', [
|
|
'platform' => $platform,
|
|
'accounts' => MarketingAccountBill::platform($platform)
|
|
->orderBy('bill_date', 'desc')
|
|
->orderBy('id', 'desc')
|
|
->paginate(setting('default.list_limit', 25)),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 校验并返回有效平台标识
|
|
*/
|
|
private function resolvePlatform(string $platform): string
|
|
{
|
|
abort_unless(array_key_exists($platform, self::PLATFORMS), 404);
|
|
|
|
return $platform;
|
|
}
|
|
|
|
/**
|
|
* 获取平台中文标题
|
|
*/
|
|
private function platformTitle(string $platform): string
|
|
{
|
|
return trans('marketing_account_bills.' . $platform);
|
|
}
|
|
}
|