You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确调用带参数的Eloquent方法earnedByStaff?

问题描述

在StaffController中获取员工交易数据时,调用Transaction模型的earnedByStaff($staff)方法遇到两个错误:

  1. 链式调用Transaction::thisMerchant()->earnedByStaff($staff)时,提示Builder::earnedByStaff()方法未定义;
  2. 静态调用Transaction::earnedByStaff($staff)时,提示非静态方法不能静态调用。

相关代码如下:

StaffController.php

$transactions = Transaction::thisMerchant()
    ->earnedByStaff($staff)
    ->where(function ($q) use ($staffID) {
        $q->where('staff_id', $staffID)
          ->orWhere(function ($qq) use ($staffID) {
            $qq
              ->whereNull('staff_id')
              ->whereHas('items', function ($qqq) use ($staffID) {
                $qqq->where('staff_id', $staffID);
              });
          })
          ->orWhereHas('associateCommissions', function ($qq) use ($staffID) {
            $qq->where('staff_id', $staffID);
          });
    })
    ->when($start_date && $end_date, function ($q) use (
        $start_date,
        $end_date
    ) {
        $q->whereBetween(\DB::raw('date(date)'), [
            $start_date . ' 00:00:00',
            $end_date . ' 23:59:59',
        ]);
    })
    ->with('client')
    ->orderBy('date', 'DESC')
    ->where('is_void', null)
    ->where('is_draft', null)
    ->with('items.sellable.sellable')
    ->with('associateCommissions')
    ->paginate(10);

Transaction.php

public function earnedFromTransaction($staff_id)
{
    $staff = Staff::find($staff_id);
    if ($this->is_void == '1') {
        return 0;
    }

    if ($this->provider() == 'Empty') {
        return 0;
    }

    if ($this->provider() == 'Split') {
        $amounts = Titem::where('transaction_id', $this->id)
            ->where('staff_id', $staff_id)
            ->whereHas('product', function ($q) {
                $q->whereNull('commission');
            })
            ->whereHas('transaction', function ($q) {
                $q->where('is_void', null);
            })
            ->sum('frozen_staff_commission');

        $discounts = Titem::where('transaction_id', $this->id)
            ->where('staff_id', $staff_id)
            ->whereHas('product', function ($q) {
                $q->whereNull('commission');
            })
            ->whereHas('transaction', function ($q) {
                $q->where('is_void', null);
            })
            ->sum('discount');

        // When the frozen staff rate is zero, just give sellable commission
        $titem_commissions = Titem::where('transaction_id', $this->id)
            ->where('staff_id', $staff_id)
            ->where('frozen_staff_commission', '<=', 0)
            ->whereHas('product', function ($q) {
                $q->whereNotNull('commission');
            })
            ->sum('commission');

        $total =
            floatval($amounts) +
            floatval($titem_commissions) -
            floatval($discounts);

        return $total;
    }

    return floatval($this->frozen_staff_commission);
}

public function earnedByStaff(Staff $staff)
{
    return StaffCommissionEngine::earnedFromTransaction($this, $staff);
}
解决方案

错误原因

  • 第一种错误:Transaction::thisMerchant()返回的是查询构造器(Builder)实例,而earnedByStaff是Transaction模型的实例方法,只能在单个Transaction对象上调用,没法直接链式调用在构造器上。
  • 第二种错误:earnedByStaff是非静态方法,必须通过模型实例调用,不能用::静态调用。

根据实际需求分两种场景处理:


场景1:给每笔交易计算对应员工的佣金

如果只是想获取交易数据后,算出该员工在每笔交易里赚的佣金,不需要过滤交易,先查交易再处理:

  1. 先获取交易分页数据:
$transactions = Transaction::thisMerchant()
    ->where(function ($q) use ($staffID) {
        // 原有where逻辑保持不变
        $q->where('staff_id', $staffID)
          ->orWhere(function ($qq) use ($staffID) {
            $qq
              ->whereNull('staff_id')
              ->whereHas('items', function ($qqq) use ($staffID) {
                $qqq->where('staff_id', $staffID);
              });
          })
          ->orWhereHas('associateCommissions', function ($qq) use ($staffID) {
            $qq->where('staff_id', $staffID);
          });
    })
    ->when($start_date && $end_date, function ($q) use ($start_date, $end_date) {
        $q->whereBetween(\DB::raw('date(date)'), [
            $start_date . ' 00:00:00',
            $end_date . ' 23:59:59',
        ]);
    })
    ->with('client', 'items.sellable.sellable', 'associateCommissions')
    ->orderBy('date', 'DESC')
    ->where('is_void', null)
    ->where('is_draft', null)
    ->paginate(10);
  1. 遍历交易集合,调用方法计算佣金:
    用集合的map方法给每个交易新增佣金字段:
$transactions->getCollection()->map(function ($transaction) use ($staff) {
    $transaction->staff_earned = $transaction->earnedByStaff($staff);
    return $transaction;
});

场景2:筛选出该员工能赚佣金的交易

如果要过滤出该员工有佣金收入的交易,需要把earnedByStaff改成Laravel查询作用域,这样就能在构造器上链式调用:

  1. 修改Transaction模型,添加作用域方法:
// 方法名必须以scope开头,符合Laravel作用域规范
public function scopeEarnedByStaff($query, Staff $staff)
{
    // 这里根据StaffCommissionEngine的佣金计算逻辑,编写对应的查询条件
    // 示例(需结合实际业务调整):
    return $query->where(function ($q) use ($staff) {
        // 筛选员工参与的交易
        $q->where('staff_id', $staff->id)
          ->orWhereHas('items', function ($qq) use ($staff) {
              $qq->where('staff_id', $staff->id);
          })
          ->orWhereHas('associateCommissions', function ($qq) use ($staff) {
              $qq->where('staff_id', $staff->id);
          });
        // 排除无效交易
        $q->where('is_void', null)->where('is_draft', null);
    });
}
  1. 在控制器中调用作用域:
$transactions = Transaction::thisMerchant()
    ->earnedByStaff($staff) // 现在可以正常链式调用
    ->when($start_date && $end_date, function ($q) use ($start_date, $end_date) {
        $q->whereBetween(\DB::raw('date(date)'), [
            $start_date . ' 00:00:00',
            $end_date . ' 23:59:59',
        ]);
    })
    ->with('client', 'items.sellable.sellable', 'associateCommissions')
    ->orderBy('date', 'DESC')
    ->paginate(10);

补充说明

  • 原earnedByStaff是实例方法,用于计算单条交易的佣金;查询作用域用于筛选交易集合,根据实际需求选择即可。
  • 如果StaffCommissionEngine::earnedFromTransaction的逻辑没法直接转成数据库查询条件,优先用场景1的方式处理。

内容的提问来源于stack exchange,提问作者davidkihara

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 22:55:34