Procházet zdrojové kódy

费用新增和研发辅助帐新增

gogs před 2 měsíci
rodič
revize
6192a837d2

+ 96 - 0
app/Http/Controllers/Api/AuxiliaryAccountController.php

@@ -0,0 +1,96 @@
+<?php
+
+namespace App\Http\Controllers\Api;
+
+use App\Service\AuxiliaryAccountService;
+use Illuminate\Http\Request;
+
+class AuxiliaryAccountController extends BaseController
+{
+    public function auxiliaryAccountList(Request $request)
+    {
+        $service = new AuxiliaryAccountService();
+        $user = $request->userData;
+        list($status,$data) = $service->auxiliaryAccountList($request->all(),$user);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
+
+    public function auxiliaryAccountSummary(Request $request)
+    {
+        $service = new AuxiliaryAccountService();
+        $user = $request->userData;
+        list($status,$data) = $service->auxiliaryAccountSummary($request->all(),$user);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
+
+
+    public function auxiliaryAccountAdd(Request $request)
+    {
+        $service = new AuxiliaryAccountService();
+        $user = $request->userData;
+        list($status,$data) = $service->auxiliaryAccountAdd($request->all(),$user);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+
+    }
+
+    public function auxiliaryAccountEdit(Request $request)
+    {
+        $service = new AuxiliaryAccountService();
+        $user = $request->userData;
+        list($status,$data) = $service->auxiliaryAccountEdit($request->all(),$user);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+
+    }
+
+
+    public function auxiliaryAccountDel(Request $request)
+    {
+        $service = new AuxiliaryAccountService();
+        $user = $request->userData;
+        list($status,$data) = $service->auxiliaryAccountDel($request->all(),$user);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+
+    }
+
+
+    public function auxiliaryAccountDetail(Request $request)
+    {
+        $service = new AuxiliaryAccountService();
+        $user = $request->userData;
+        list($status,$data) = $service->auxiliaryAccountDetail($request->all(),$user);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+
+    }
+
+
+}

+ 83 - 0
app/Http/Controllers/Api/ExpenseClaimsController.php

@@ -0,0 +1,83 @@
+<?php
+
+namespace App\Http\Controllers\Api;
+
+use App\Service\ExpenseClaimsService;
+use Illuminate\Http\Request;
+
+class ExpenseClaimsController extends BaseController
+{
+    public function expenseClaimsList(Request $request)
+    {
+        $service = new ExpenseClaimsService();
+        $user = $request->userData;
+        list($status,$data) = $service->expenseClaimsList($request->all(),$user);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
+
+
+    public function expenseClaimsAdd(Request $request)
+    {
+        $service = new ExpenseClaimsService();
+        $user = $request->userData;
+        list($status,$data) = $service->expenseClaimsAdd($request->all(),$user);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+
+    }
+
+    public function expenseClaimsEdit(Request $request)
+    {
+        $service = new ExpenseClaimsService();
+        $user = $request->userData;
+        list($status,$data) = $service->expenseClaimsEdit($request->all(),$user);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+
+    }
+
+
+    public function expenseClaimsDel(Request $request)
+    {
+        $service = new ExpenseClaimsService();
+        $user = $request->userData;
+        list($status,$data) = $service->expenseClaimsDel($request->all(),$user);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+
+    }
+
+
+    public function expenseClaimsDetail(Request $request)
+    {
+        $service = new ExpenseClaimsService();
+        $user = $request->userData;
+        list($status,$data) = $service->expenseClaimsDetail($request->all(),$user);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+
+    }
+
+
+}

+ 17 - 0
app/Model/AuxiliaryAccount.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace App\Model;
+
+class AuxiliaryAccount extends DataScopeBaseModel
+{
+    //设备日工时单
+    protected $table = "auxiliary_account"; //指定表
+    const CREATED_AT = 'crt_time';
+    const UPDATED_AT = 'upd_time';
+    protected $dateFormat = 'U';
+    const employee_column = "crt_id";
+
+    public static $field = ['id','code','crt_time','month',"crt_id"];
+
+    const Order_type = "auxiliary_account";
+}

+ 14 - 0
app/Model/AuxiliaryAccountDetails.php

@@ -0,0 +1,14 @@
+<?php
+
+namespace App\Model;
+
+class AuxiliaryAccountDetails extends DataScopeBaseModel
+{
+    //设备日工时单
+    protected $table = "auxiliary_account_details"; //指定表
+    const CREATED_AT = 'crt_time';
+    const UPDATED_AT = 'upd_time';
+    protected $dateFormat = 'U';
+    const employee_column = "crt_id";
+    const Order_type = "auxiliary_account_details";
+}

+ 17 - 0
app/Model/ExpenseClaims.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace App\Model;
+
+class ExpenseClaims extends DataScopeBaseModel
+{
+    //设备日工时单
+    protected $table = "expense_claims"; //指定表
+    const CREATED_AT = 'crt_time';
+    const UPDATED_AT = 'upd_time';
+    protected $dateFormat = 'U';
+    const employee_column = "crt_id";
+
+    public static $field = ['id','code','crt_time','month',"crt_id"];
+
+    const Order_type = "expense_claims";
+}

+ 17 - 0
app/Model/ExpenseClaimsDetails.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace App\Model;
+
+class ExpenseClaimsDetails extends DataScopeBaseModel
+{
+    //设备日工时单
+    protected $table = "expense_claims_details"; //指定表
+    const CREATED_AT = 'crt_time';
+    const UPDATED_AT = 'upd_time';
+    protected $dateFormat = 'U';
+    const employee_column = "crt_id";
+
+    public static $field = ['id','item_id','employee_id','fee_id',"amount","amount","remark","remark","claim_date","entrust_type","expense_type","expense_attachments"];
+
+    const Order_type = "expense_claims_details";
+}

+ 357 - 0
app/Service/AuxiliaryAccountService.php

@@ -0,0 +1,357 @@
+<?php
+
+namespace App\Service;
+
+use App\Model\AuxiliaryAccount;
+use App\Model\AuxiliaryAccountDetails;
+use App\Model\CalendarDetails;
+use App\Model\Device;
+use App\Model\Employee;
+use App\Model\ExpenseClaims;
+use App\Model\ExpenseClaimsDetails;
+use App\Model\Fee;
+use App\Model\Item;
+use App\Model\ItemDetails;
+use App\Model\MonthlyDdOrder;
+use App\Model\MonthlyPsOrder;
+use App\Model\MonthlyPsOrderDetails;
+use App\Model\MonthlyPwOrderDetails;
+use App\Model\RuleSet;
+use App\Model\RuleSetDetails;
+use Illuminate\Support\Facades\DB;
+
+class AuxiliaryAccountService extends Service
+{
+    public function auxiliaryAccountList($data,$user){
+        $model = $this->setCommon($data, $user);
+        $list = $this->limit($model,'',$data);
+        $list = $this->fillData($list);
+
+        return [true, $list];
+    }
+    //
+
+    private function setCommon($data,$user, $field = []){
+        if(empty($field)) $field = AuxiliaryAccount::$field;
+        $data['top_depart_id'] = $user['top_depart_id'];
+        $model = ExpenseClaims::Clear($user,$data);
+        $model = $model->where('del_time',0)
+            ->select($field)
+            ->orderby('month', 'desc');
+        if(! empty($data['month'])) $model->where('month', $data['month']);
+        if(! empty($data['code'])) $model->where('code', 'LIKE', '%'.$data['code'].'%');
+        return $model;
+
+    }
+    public function fillData($data){
+        if(empty($data['data'])) return $data;
+
+        $emp = (new EmployeeService())->getEmployeeMap(array_unique(array_column($data['data'],'crt_id')));
+
+        foreach ($data['data'] as $key => $value){
+            $data['data'][$key]['crt_time'] = $value['crt_time'] ? date('Y-m-d H:i:s',$value['crt_time']) : '';
+            $data['data'][$key]['crt_name'] = $emp[$value['crt_id']] ?? '';
+            $data['data'][$key]['month'] =  $value['month'] ? date('Y-m',$value['month']) : '';
+        }
+        return $data;
+    }
+
+    public function auxiliaryAccountSummary($data,$user){
+        //传参月份
+        if(!isset($data['month'])) return [201,'月份必传'];
+        $month = $data['month'];
+        $monthStart = strtotime($month);
+        $monthEnd = strtotime("$month +1 month") - 1;
+        //获取员工汇总月份工资
+        list($status,$employee_month_amount) = $this->employeeMonthAmount($data,$user,$monthStart,$monthEnd);
+        if (!$status) return [$status,$employee_month_amount];
+        //获取设备折旧费用
+        list($status,$device_month_amount) = $this->deviceMonthAmount($data,$user,$monthStart,$monthEnd);
+        if (!$status) return [$status,$device_month_amount];
+        //获取费用汇总的费用数据
+        list($status,$fee_month_amount) = $this->feeMonthAmount($data,$user,$monthStart,$monthEnd);
+        if (!$status) return [$status,$fee_month_amount];
+
+        return [true,[
+            "employee_month_amount" => $employee_month_amount,
+            "device_month_amount" => $device_month_amount,
+            "fee_month_amount" => $fee_month_amount,
+        ]];
+
+    }
+
+    private  function employeeMonthAmount($month,$user,$monthStart,$monthEnd){
+        $data['top_depart_id'] = $user['top_depart_id'];
+        $month_ps_order = MonthlyPsOrder::Clear($user,$data);
+        $month_ps_order_id = $month_ps_order->where("month",$monthStart)->first();
+        if(empty($month_ps_order_id)){
+            return [false,"请补充对应月份人员月度工资信息"];
+        }else{
+            $month_ps_order_id = $month_ps_order_id->id;
+        }
+        $model = MonthlyPsOrderDetails::Clear($user,$data);
+        //总金额
+        $total_amount = $model->where('main_id',$month_ps_order_id)->where('del_time',0)->sum("salary");
+
+        //委内
+        $entrust_in_amount = $model->where('main_id',$month_ps_order_id)->where("entrust_type",1)->sum("salary");
+        //委外
+        $entrust_out_amount = $model->where('main_id',$month_ps_order_id)->where("entrust_type",2)->sum("salary");
+
+        return [true,[
+            "total_amount" => $total_amount,
+            "entrust_in_amount" => $entrust_in_amount,
+            "entrust_out_amount" => $entrust_out_amount,
+        ]];
+    }
+
+    private  function deviceMonthAmount($month,$user,$monthStart,$monthEnd){
+        $data['top_depart_id'] = $user['top_depart_id'];
+        $month_ps_order = MonthlyDdOrder::Clear($user,$data);
+        $month_ps_order_id = $month_ps_order->where('del_time',0)->where("month",$monthStart)->first();
+        if(empty($month_ps_order_id)){
+            return [false,"请补充对应月份设备月度折旧信息"];
+        }else{
+            $month_ps_order_id = $month_ps_order_id->id;
+        }
+        $model = MonthlyPsOrderDetails::Clear($user,$data);
+        //总金额
+        $total_amount = $model->where('main_id',$month_ps_order_id)->sum("depreciation_amount");
+        return [true,[
+            "total_amount" => $total_amount,
+        ]];
+    }
+    private  function feeMonthAmount($month,$user,$monthStart,$monthEnd){
+        $data['top_depart_id'] = $user['top_depart_id'];
+        $month_ps_order = ExpenseClaims::Clear($user,$data);
+        $month_ps_order_id = $month_ps_order->where('del_time',0)->where("month",$monthStart)->first();
+        if(empty($month_ps_order_id)){
+            return [false,"请补充对应月份设备月度折旧信息"];
+        }else{
+            $month_ps_order_id = $month_ps_order_id->id;
+        }
+        $model = MonthlyPsOrderDetails::Clear($user,$data);
+        //总金额
+        $list = $model->where('expense_claims_id',$month_ps_order_id)->select("fee_id","amount","remark","entrust_type")->get()->toArray();
+        ///分组
+        $fee_type_list = Fee::Clear($user,$data)->where('del_time',0)->select("title","id","parent_id")->get()->toArray();
+        return $this->groupListByRoot($list,$fee_type_list);
+
+    }
+
+    /**
+     * 将报销明细按照一级费用分类进行分组
+     * * @param array $list          报销明细列表 (含 fee_id, amount 等)
+     * @param array $fee_type_list 费用类型树 (含 id, parent_id, title)
+     * @return array
+     */
+    public function groupListByRoot(array $list, array $fee_type_list)
+    {
+        // 1. 建立 ID 索引,方便快速查找
+        $idMap = array_column($fee_type_list, null, 'id');
+
+        // 2. 预处理映射表:让所有子 ID 直接指向它的最顶层“祖宗” ID
+        $childToRoot = [];
+        foreach ($fee_type_list as $type) {
+            $current = $type;
+            // 向上追溯直到 parent_id 为 0,即找到一级分类
+            while ($current['parent_id'] != 0 && isset($idMap[$current['parent_id']])) {
+                $current = $idMap[$current['parent_id']];
+            }
+            $childToRoot[$type['id']] = [
+                'id'    => $current['id'],
+                'title' => $current['title']
+            ];
+        }
+
+        // 3. 遍历明细数据进行分组
+        $grouped = [];
+        foreach ($list as $item) {
+            $feeId = $item['fee_id'];
+            // 获取该费用对应的一级分类信息
+            $rootInfo = $childToRoot[$feeId] ?? ['id' => 0, 'title' => '其他费用'];
+            $rootId   = $rootInfo['id'];
+
+            if (!isset($grouped[$rootId])) {
+                $grouped[$rootId] = [
+                    'first_level_id'    => $rootId,
+                    'first_level_title' => $rootInfo['title'],
+                    'details'           => []
+                ];
+            }
+
+            $grouped[$rootId]['details'][]    = $item;
+        }
+
+        // 4. 重置数组索引并返回
+        return array_values($grouped);
+    }
+
+    public function auxiliaryAccountAdd($data,$user){
+        list($status,$msg) = $this->auxiliaryAccountRule($data, $user);
+        if(!$status) return [$status,$msg];
+        //费用报销结构
+        try {
+            DB::beginTransaction();
+
+            $model = new ExpenseClaims();
+            $model->code = $this->generateBillNo([
+                'top_depart_id' => $user['top_depart_id'],
+                'type' => ExpenseClaims::Order_type,
+                'month' => date("Ym", strtotime($data['month']))
+            ]);
+            $model->month = $data['order_time'] ?? 0;
+            $model->type = $data['type'];
+            $model->crt_id = $user['id'];
+            $model->top_depart_id = $data['top_depart_id'];
+            $model->save();
+
+            $this->saveDetail($model->id, time(), $data);
+
+            DB::commit();
+        }catch (\Exception $exception){
+            DB::rollBack();
+            return [false,$exception->getMessage()];
+        }
+
+        return [true, ''];
+    }
+    private function saveDetail($id, $time, $data){
+        if(! empty($data['details'])){
+            $unit = [];
+            foreach ($data['details'] as $value){
+                $unit[] = [
+                    'auxiliary_account_id' => $id,
+                    'voucher_date' => strtotime($value['voucher_date']),
+                    'voucher_type' => $value['voucher_type'],
+                    'voucher_no' => $value['voucher_no'],
+                    'voucher_remark' => $value['voucher_remark'],
+                    'voucher_amount' => $value['voucher_amount'],
+                    'entrust_type' => $value['entrust_type'],
+                    'type' => $value['type'],
+                    'fee_id' => $value['fee_id']??0,
+                    'remark' => $value['remark']??"",
+                    'entrust1_amount' => $value['entrust1_amount']??0,
+                    'entrust2_amount' => $value['entrust2_amount']??0,
+                    'aggregation_amount' => $value['aggregation_amount']??00,
+                    'total_amount' => $value['total_amount'],
+                    'top_depart_id' => $value['top_depart_id'],
+                    'crt_time' => $time,
+                ];
+            }
+            if(!empty($unit)) AuxiliaryAccountDetails::insert($unit);
+        }
+    }
+
+    private function auxiliaryAccountRule($data,$user){
+        if(!isset($data['month'])) return [false,"月份必传"];
+        $monthStr = $data['month']; // 假设是 "2026-03"
+        $monthStart = strtotime($monthStr); // 2026-03-01 00:00:00
+        // 获取该月最后一秒:下个月 1 号减去 1 秒
+        $monthEnd = strtotime("$monthStr +1 month") - 1;
+        foreach ($data['detail'] as $index => $item) {
+            if (!isset($item['voucher_date'])) {
+                return [false, "第" . ($index + 1) . "凭证日期缺失"];
+            }
+            if (!isset($item['voucher_no'])) {
+                return [false, "第" . ($index + 1) . "凭证号数缺失"];
+            }
+            if (!isset($item['voucher_amount'])) {
+                return [false, "第" . ($index + 1) . "凭证记载金额缺失"];
+            }
+            if (!isset($item['voucher_type'])) {
+                return [false, "第" . ($index + 1) . "凭证类型缺失"];
+            }
+            if (!isset($item['aggregation_amount'])) {
+                return [false, "第" . ($index + 1) . "凭证归集金额缺失"];
+            }
+            if (!isset($item['voucher_remark'])) {
+                return [false, "第" . ($index + 1) . "凭证摘要缺失"];
+            }
+            // 将报销日期转换为时间戳
+            $claimTime = strtotime($item['claim_date']);
+            // 判断:claim_date 必须早于 month
+            // 如果 claim_date 是 2026-02-28,而 month 是 2026-03-01,则校验通过
+            if ($claimTime < $monthStart || $claimTime > $monthEnd) {
+                return [false, "第" . ($index + 1) . "凭证日期必须早于当前结算月份(" . $data['month'] . ")"];
+            }
+        }
+        return [true,""];
+    }
+
+    public function auxiliaryAccountEdit($data,$user){
+        list($status,$msg) = $this->auxiliaryAccountRule($data, $user, false);
+        if(!$status) return [$status,$msg];
+
+        try {
+            DB::beginTransaction();
+
+            $model = AuxiliaryAccount::where('id',$data['id'])->first();
+            //不允许修改头部
+//            $model->save();
+            $time = time();
+            AuxiliaryAccountDetails::where('del_time',0)
+                ->where('auxiliary_account_id', $model->id)
+                ->update(['del_time' => $time]);
+            $this->saveDetail($model->id, $time, $data);
+
+            DB::commit();
+        }catch (\Exception $exception){
+            DB::rollBack();
+            return [false,$exception->getMessage()];
+        }
+
+        return [true, ''];
+    }
+
+    public function auxiliaryAccountDel($data){
+        if($this->isEmpty($data,'id')) return [false,'请选择数据!'];
+
+        try {
+            DB::beginTransaction();
+            $time = time();
+
+            AuxiliaryAccount::where('del_time',0)
+                ->whereIn('id',$data['id'])
+                ->update(['del_time' => $time]);
+
+            AuxiliaryAccountDetails::where('del_time',0)
+                ->whereIn('auxiliary_account_id', $data['id'])
+                ->update(['del_time' => $time]);
+
+            DB::commit();
+        }catch (\Exception $exception){
+            DB::rollBack();
+            return [false,$exception->getMessage()];
+        }
+
+        return [true, ''];
+    }
+
+    public function auxiliaryAccountDetail($data, $user){
+        if($this->isEmpty($data,'id')) return [false,'请选择数据!'];
+        $customer = AuxiliaryAccount::where('del_time',0)
+            ->where('id',$data['id'])
+            ->first();
+        if(empty($customer)) return [false,'单据不存在或已被删除'];
+        $customer = $customer->toArray();
+        $customer['crt_name'] = Employee::where('id',$customer['crt_id'])->value('title');
+        $customer['crt_time'] = $customer['crt_time'] ? date("Y-m-d H:i:s",$customer['crt_time']): '';
+
+        $details = $this->getDetail($data['id']);
+        $customer = array_merge($customer, $details);
+
+        return [true, $customer];
+    }
+
+    private function getDetail($id){
+        $data = AuxiliaryAccountDetails::where('del_time',0)
+            ->where('expense_claims_id', $id)
+            ->select('*')
+            ->get()->toArray();
+        return $data;
+    }
+
+
+
+}

+ 202 - 0
app/Service/ExpenseClaimsService.php

@@ -0,0 +1,202 @@
+<?php
+
+namespace App\Service;
+
+use App\Model\CalendarDetails;
+use App\Model\Device;
+use App\Model\Employee;
+use App\Model\ExpenseClaims;
+use App\Model\ExpenseClaimsDetails;
+use App\Model\Item;
+use App\Model\ItemDetails;
+use App\Model\RuleSet;
+use App\Model\RuleSetDetails;
+use Illuminate\Support\Facades\DB;
+
+class ExpenseClaimsService extends Service
+{
+    public function expenseClaimsList($data,$user){
+        $model = $this->expenseClaimsSetCommon($data, $user);
+        $list = $this->limit($model,'',$data);
+        $list = $this->fillData($list);
+
+        return [true, $list];
+    }
+
+    private function expenseClaimsSetCommon($data,$user, $field = []){
+        if(empty($field)) $field = ExpenseClaims::$field;
+        $data['top_depart_id'] = $user['top_depart_id'];
+        $model = ExpenseClaims::Clear($user,$data);
+        $model = $model->where('del_time',0)
+            ->select($field)
+            ->orderby('month', 'desc');
+        if(! empty($data['month'])) $model->where('month', $data['month']);
+        if(! empty($data['code'])) $model->where('code', 'LIKE', '%'.$data['code'].'%');
+        return $model;
+
+    }
+    public function fillData($data){
+        if(empty($data['data'])) return $data;
+
+        $emp = (new EmployeeService())->getEmployeeMap(array_unique(array_column($data['data'],'crt_id')));
+
+        foreach ($data['data'] as $key => $value){
+            $data['data'][$key]['crt_time'] = $value['crt_time'] ? date('Y-m-d H:i:s',$value['crt_time']) : '';
+            $data['data'][$key]['crt_name'] = $emp[$value['crt_id']] ?? '';
+            $data['data'][$key]['month'] =  $value['month'] ? date('Y-m',$value['month']) : '';
+        }
+        return $data;
+    }
+
+    public function expenseClaimsAdd($data,$user){
+        list($status,$msg) = $this->expenseClaimsRule($data, $user);
+        if(!$status) return [$status,$msg];
+        //费用报销结构
+        try {
+            DB::beginTransaction();
+            $month = strtotime(date("Ymd", strtotime($data['month'])));
+            $model = new ExpenseClaims();
+            $model->code = $this->generateBillNo([
+                'top_depart_id' => $user['top_depart_id'],
+                'type' => ExpenseClaims::Order_type,
+                'month' => $month
+            ]);
+            $model->month =  $month;
+            $model->type = $data['type'];
+            $model->crt_id = $user['id'];
+            $model->top_depart_id = $data['top_depart_id'];
+            $model->save();
+
+            $this->saveDetail($model->id, time(), $data);
+
+            DB::commit();
+        }catch (\Exception $exception){
+            DB::rollBack();
+            return [false,$exception->getMessage()];
+        }
+
+        return [true, ''];
+    }
+    private function saveDetail($id, $time, $data){
+        if(! empty($data['details'])){
+            $unit = [];
+            foreach ($data['details'] as $value){
+                $unit[] = [
+                    'expense_claims_id' => $id,
+                    'item_id' => $value['item_id'],
+                    'employee_id' => $value['employee_id'],
+                    'fee_id' => $value['fee_id'],
+                    'amount' => $value['amount'],
+                    'remark' => $value['remark'],
+                    'claim_date' => $value['claim_date'],
+                    'entrust_type' => $value['entrust_type'],
+                    'expense_type' => $value['expense_type'],
+                    'expense_attachments' => $value['expense_attachments'],
+                    'top_depart_id' => $value['top_depart_id'],
+                    'crt_time' => $time,
+                ];
+            }
+            if(!empty($unit)) ExpenseClaimsDetails::insert($unit);
+        }
+    }
+
+    private function expenseClaimsRule($data,$user){
+        if(!isset($data['month'])) return [false,"月份必传"];
+        $monthStr = $data['month']; // 假设是 "2026-03"
+        $monthStart = strtotime($monthStr); // 2026-03-01 00:00:00
+        // 获取该月最后一秒:下个月 1 号减去 1 秒
+        $monthEnd = strtotime("$monthStr +1 month") - 1;
+        foreach ($data['detail'] as $index => $item) {
+            if (!isset($item['claim_date'])) {
+                return [false, "第" . ($index + 1) . "项报销日期缺失"];
+            }
+            // 将报销日期转换为时间戳
+            $claimTime = strtotime($item['claim_date']);
+            // 判断:claim_date 必须早于 month
+            // 如果 claim_date 是 2026-02-28,而 month 是 2026-03-01,则校验通过
+            if ($claimTime < $monthStart || $claimTime > $monthEnd) {
+                return [false, "第" . ($index + 1) . "项报销日期必须早于当前结算月份(" . $data['month'] . ")"];
+            }
+        }
+        return [true,""];
+    }
+
+    public function expenseClaimsEdit($data,$user){
+        list($status,$msg) = $this->expenseClaimsRule($data, $user, false);
+        if(!$status) return [$status,$msg];
+
+        try {
+            DB::beginTransaction();
+            $month = strtotime(date("Ymd", strtotime($data['month'])));
+            $model = ExpenseClaims::where('id',$data['id'])->first();
+            $model->month =  $month;
+            $model->type = $data['type'];
+            $model->crt_id = $user['id'];
+            $model->save();
+
+            $time = time();
+            ExpenseClaimsDetails::where('del_time',0)
+                ->where('expense_claims_id', $model->id)
+                ->update(['del_time' => $time]);
+            $this->saveDetail($model->id, $time, $data);
+
+            DB::commit();
+        }catch (\Exception $exception){
+            DB::rollBack();
+            return [false,$exception->getMessage()];
+        }
+
+        return [true, ''];
+    }
+
+    public function expenseClaimsDel($data){
+        if($this->isEmpty($data,'id')) return [false,'请选择数据!'];
+
+        try {
+            DB::beginTransaction();
+            $time = time();
+
+            ExpenseClaims::where('del_time',0)
+                ->whereIn('id',$data['id'])
+                ->update(['del_time' => $time]);
+
+            ExpenseClaimsDetails::where('del_time',0)
+                ->whereIn('expense_claims_id', $data['id'])
+                ->update(['del_time' => $time]);
+
+            DB::commit();
+        }catch (\Exception $exception){
+            DB::rollBack();
+            return [false,$exception->getMessage()];
+        }
+
+        return [true, ''];
+    }
+
+    public function expenseClaimsDetail($data, $user){
+        if($this->isEmpty($data,'id')) return [false,'请选择数据!'];
+        $customer = ExpenseClaims::where('del_time',0)
+            ->where('id',$data['id'])
+            ->first();
+        if(empty($customer)) return [false,'单据不存在或已被删除'];
+        $customer = $customer->toArray();
+        $customer['crt_name'] = Employee::where('id',$customer['crt_id'])->value('title');
+        $customer['crt_time'] = $customer['crt_time'] ? date("Y-m-d H:i:s",$customer['crt_time']): '';
+
+        $details = $this->getDetail($data['id']);
+        $customer = array_merge($customer, $details);
+
+        return [true, $customer];
+    }
+
+    private function getDetail($id){
+        $data = ExpenseClaimsDetails::where('del_time',0)
+            ->where('expense_claims_id', $id)
+            ->select('*')
+            ->get()->toArray();
+        return $data;
+    }
+
+
+
+}

+ 18 - 0
routes/api.php

@@ -163,5 +163,23 @@ Route::group(['middleware'=> ['checkLogin']],function ($route){
     //获取默认月考勤数据 人和设备
     $route->any('isSetMonthCalendar', 'Api\RuleSetController@isSetMonthCalendar');
 
+    //费用报销单
+    $route->any('expenseClaimsList', 'Api\ExpenseClaimsController@expenseClaimsList');
+    $route->any('expenseClaimsAdd', 'Api\ExpenseClaimsController@expenseClaimsAdd');
+    $route->any('expenseClaimsEdit', 'Api\ExpenseClaimsController@expenseClaimsEdit');
+    $route->any('expenseClaimsDel', 'Api\ExpenseClaimsController@expenseClaimsDel');
+    $route->any('expenseClaimsDetail', 'Api\ExpenseClaimsController@expenseClaimsDetail');
+
+
+    //研发支出辅助帐
+    $route->any('auxiliaryAccountList', 'Api\AuxiliaryAccountController@auxiliaryAccountList');
+    $route->any('auxiliaryAccountAdd', 'Api\AuxiliaryAccountController@auxiliaryAccountAdd');
+    $route->any('auxiliaryAccountEdit', 'Api\AuxiliaryAccountController@auxiliaryAccountEdit');
+    $route->any('auxiliaryAccountDel', 'Api\AuxiliaryAccountController@auxiliaryAccountDel');
+    $route->any('auxiliaryAccountDetail', 'Api\AuxiliaryAccountController@auxiliaryAccountDetail');
+    ////需要一个单独的接口根据月份汇总新增的研发支出辅助帐
+    $route->any('auxiliaryAccountSummary', 'Api\AuxiliaryAccountController@auxiliaryAccountSummary');
+
+
 });