/home/techb158/ileadtechnology.com/SSM/app/Repositories/student
Edit: /home/techb158/ileadtechnology.com/SSM/app/Repositories/student/StudentRecordRepository.php (52903B)
student_record = $student_record;
$this->student_fee_record = $student_fee_record;
$this->transport_circle = $transport_circle;
$this->fee_concession = $fee_concession;
$this->student_optional_fee_record = $student_optional_fee_record;
$this->account = $account;
$this->payment_method = $payment_method;
$this->fee_installment = $fee_installment;
$this->transaction = $transaction;
$this->student_fee_record_detail = $student_fee_record_detail;
$this->course_group = $course_group;
$this->batch = $batch;
$this->fee_allocation = $fee_allocation;
$this->employee = $employee;
$this->admission = $admission;
$this->id_card_template = $id_card_template;
}
/**
* Find student with given id or throw an error.
*
* @param integer $id
* @param integer $record_id
* @return StudentRecord
*/
public function findOrFail($id, $record_id, $field = 'message') {
$student_record = $this->student_record->whereHas('student', function ($q) use ($id) {
$q->where('id', $id);
})->filterById($record_id)->first();
if (!$student_record) {
throw ValidationException::withMessages([$field => trans('student.could_not_find')]);
}
return $student_record;
}
/**
* Find student with given uuid or throw an error.
*
* @param string $uuid
* @param integer $record_id
* @return StudentRecord
*/
public function findByUuidOrFail($uuid, $record_id, $field = 'message') {
$student_record = $this->student_record->whereHas('student', function ($q) use ($uuid) {
$q->where('uuid', $uuid);
})->filterById($record_id)->first();
if (!$student_record) {
throw ValidationException::withMessages([$field => trans('student.could_not_find')]);
}
return $student_record;
}
/**
* Get record edit requisite.
*
* @return Array
*/
public function getRecordPreRequisite() {
$batches = $this->course_group->getBatchOption();
return compact('batches');
}
/**
* Update student record.
*
* @param StudentRecord $student_record
* @param array $params
* @return void
*/
public function updateRecord(StudentRecord $student_record, $params) {
if ($student_record->academic_session_id != config('config.default_academic_session.id')) {
throw ValidationException::withMessages(['message' => trans('student.could_not_find')]);
}
beginTransaction();
$admission = $student_record->admission;
$prefix = gv($params, 'prefix');
$number = gv($params, 'number');
if (!is_numeric($number)) {
throw ValidationException::withMessages(['number' => trans('validation.integer', ['attribute' => trans('student.admission_number')])]);
}
if ($this->admission->where('id', '!=', $admission->id)->filterByNumber($number)->filterByPrefix($prefix)->count()) {
throw ValidationException::withMessages(['number' => trans('validation.unique', ['attribute' => trans('student.admission_number')])]);
}
$admission->prefix = $prefix;
$admission->number = $number;
$next_student_records = $this->student_record->filterByStudentId($student_record->student_id)->where('date_of_entry', '>', toDate($student_record->date_of_entry))->count();
if ($next_student_records) {
throw ValidationException::withMessages(['message' => trans('student.no_modification_allowed_in_intermediate_records')]);
}
$first_student_record = $this->student_record->filterByAdmissionId($admission->id)->orderBy('date_of_entry', 'asc')->first();
$date_of_entry = toDate(gv($params, 'date_of_entry'));
if ($date_of_entry != toDate($student_record->date_of_entry)) {
$previous_student_record = $this->student_record->filterByStudentId($student_record->student_id)->where('date_of_entry', '<', toDate($student_record->date_of_entry))->orderBy('date_of_entry', 'desc')->first();
if ($previous_student_record && toDate($previous_student_record->date_of_exit) && toDate($previous_student_record->date_of_exit) >= $date_of_entry) {
throw ValidationException::withMessages(['message' => trans('student.record_is_overlapping')]);
}
if ($previous_student_record && !$previous_student_record->date_of_exit && toDate($previous_student_record->date_of_entry) >= $date_of_entry) {
throw ValidationException::withMessages(['message' => trans('student.record_is_overlapping')]);
}
if ($date_of_entry > config('config.default_academic_session.end_date')) {
throw ValidationException::withMessages(['message' => trans('student.date_of_entry_should_less_than_session_end_date')]);
}
$student_record->date_of_entry = toDate($date_of_entry);
if ($first_student_record->id == $student_record->id) {
$admission->date_of_admission = toDate($date_of_entry);
}
}
if (!$student_record->relationLoaded('studentFeeRecords')) {
$student_record->load('studentFeeRecords');
}
if (!$student_record->relationLoaded('batch')) {
$student_record->load('batch');
}
$batch_id = gv($params, 'batch_id');
$batch = $this->batch->findOrFail($batch_id);
if ($batch->id != $student_record->batch_id) {
$batch->load('feeAllocation');
$fee_allocation = $batch->feeAllocation;
$change_course_batch = false;
if ((!$fee_allocation && $batch->course_id == $student_record->batch->course_id) || ($fee_allocation && $fee_allocation->course_id && $fee_allocation->course_id == $student_record->batch->course_id)) {
$change_course_batch = true;
}
if (!$change_course_batch && $student_record->studentFeeRecords->firstWhere('status', '!=', 'unpaid')) {
throw ValidationException::withMessages(['message' => trans('student.cannot_edit_record_batch_after_fee_payment')]);
}
$student_record->batch_id = $batch->id;
}
$student_record->save();
$admission->save();
commitTransaction();
}
/**
* Update student fee.
*
* @param StudentRecord $student_record
* @param array $params
* @return Array
*/
public function setFee(StudentRecord $student_record, $params) {
$fee_groups = gv($params, 'fee_groups', []);
$transport_circle_ids = $this->transport_circle->filterBySession($student_record->academic_session_id)->get()->pluck('id')->all();
$fee_concession_ids = $this->fee_concession->filterBySession($student_record->academic_session_id)->get()->pluck('id')->all();
foreach ($fee_groups as $fee_group) {
$installments = gv($fee_group, 'installments', []);
foreach ($installments as $installment) {
$fee_installment_id = gv($installment, 'fee_installment_id');
$transport_circle_id = gv($installment, 'transport_circle_id');
$fee_concession_id = gv($installment, 'fee_concession_id');
$late_fee_applicable = gbv($installment, 'late_fee_applicable');
$late_fee_frequency = gv($installment, 'late_fee_frequency');
$due_date = toDate(gv($installment, 'due_date'));
$late_fee = gv($installment, 'late_fee', 0);
$remarks = gv($installment, 'remarks');
if ($late_fee_applicable && !$late_fee_frequency) {
throw ValidationException::withMessages(['message' => trans('validation.numeric', ['attribute' => trans('finance.late_fee_frequency')])]);
}
if ($late_fee_applicable && (!$late_fee || $late_fee < 0)) {
throw ValidationException::withMessages(['message' => trans('validation.numeric', ['attribute' => trans('finance.late_fee')])]);
}
$student_fee_record = $this->student_fee_record->with('studentOptionalFeeRecords', 'feeInstallment')->filterByStudentRecordId($student_record->id)->filterByFeeInstallmentId($fee_installment_id)->first();
if (!$student_fee_record) {
throw ValidationException::withMessages(['message' => trans('finance.could_not_find_fee_installment')]);
}
if ($transport_circle_id && !in_array($transport_circle_id, $transport_circle_ids)) {
throw ValidationException::withMessages(['message' => trans('transport.could_not_find_circle')]);
}
if ($fee_concession_id && !in_array($fee_concession_id, $fee_concession_ids)) {
throw ValidationException::withMessages(['message' => trans('finance.could_not_find_fee_concession')]);
}
$next_student_fee_record = $this->student_fee_record->with('feeInstallment')->filterByStudentRecordId($student_record->id)->where('fee_installment_id', '>', $fee_installment_id)->orderBy('fee_installment_id', 'asc')->first();
if ($next_student_fee_record && $next_student_fee_record->feeInstallment->fee_allocation_group_id == $student_fee_record->feeInstallment->fee_allocation_group_id && (($next_student_fee_record->due_date && toDate($next_student_fee_record->due_date) <= $due_date) || (!$next_student_fee_record->due_date && toDate($next_student_fee_record->feeInstallment->due_date) <= $due_date))) {
throw ValidationException::withMessages(['due_date_' . $fee_installment_id => trans('finance.due_date_greater_than_next_installment_due_date')]);
}
$previous_student_fee_record = $this->student_fee_record->with('feeInstallment')->filterByStudentRecordId($student_record->id)->where('fee_installment_id', '<', $fee_installment_id)->orderBy('fee_installment_id', 'desc')->first();
if ($previous_student_fee_record && $previous_student_fee_record->feeInstallment->fee_allocation_group_id == $student_fee_record->feeInstallment->fee_allocation_group_id && (($previous_student_fee_record->due_date && toDate($previous_student_fee_record->due_date) >= $due_date) || (!$previous_student_fee_record->due_date && toDate($previous_student_fee_record->feeInstallment->due_date) >= $due_date))) {
throw ValidationException::withMessages(['due_date_' . $fee_installment_id => trans('finance.due_date_less_than_previous_installment_due_date')]);
}
if ($student_fee_record->status == 'unpaid') {
$student_fee_record->transport_circle_id = $transport_circle_id;
$student_fee_record->fee_concession_id = $fee_concession_id;
$student_fee_record->due_date = ($student_fee_record->feeInstallment->due_date != $due_date) ? toDate($due_date) : null;
$student_fee_record->late_fee_applicable = ($student_fee_record->feeInstallment->late_fee_applicable != $late_fee_applicable) ? $late_fee_applicable : null;
$student_fee_record->late_fee_frequency = ($student_fee_record->feeInstallment->late_fee_frequency != $late_fee_frequency) ? $late_fee_frequency : null;
$student_fee_record->late_fee = ($student_fee_record->feeInstallment->late_fee != $late_fee) ? $late_fee : 0;
$student_fee_record->remarks = $remarks;
$student_fee_record->save();
$fee_heads = gv($installment, 'heads', []);
$optional_fee_head_ids = $this->student_optional_fee_record->filterByStudentFeeRecordId($student_fee_record->id)->get()->pluck('fee_head_id')->all();
$non_optional_ids = array();
$new_optional_fee_heads = array();
foreach ($fee_heads as $fee_head) {
$fee_head_id = gv($fee_head, 'id');
$is_optional = gbv($fee_head, 'is_optional');
$value = gbv($fee_head, 'value');
if ($is_optional && !$value) {
if (!in_array($fee_head_id, $optional_fee_head_ids)) {
$new_optional_fee_heads[] = array(
'student_fee_record_id' => $student_fee_record->id,
'fee_head_id' => $fee_head_id,
);
}
} else {
$non_optional_ids[] = $fee_head_id;
}
}
$this->student_optional_fee_record->insert($new_optional_fee_heads);
$this->student_optional_fee_record->filterByStudentFeeRecordId($student_fee_record->id)->whereIn('fee_head_id', $non_optional_ids)->delete();
}
}
}
}
/**
* Reset student fee.
*
* @param StudentRecord $student_record
* @param array $params
* @return Array
*/
public function resetFee(StudentRecord $student_record, $params) {
$student_record->load('studentFeeRecords');
if ($student_record->studentFeeRecords->where('status', '!=', 'unpaid')->count()) {
throw ValidationException::withMessages(['message' => trans('student.fee_cannot_reset_for_any_paid_installment')]);
}
$this->student_fee_record->where('student_record_id', $student_record->id)->delete();
$student_record->fee_allocation_id = null;
$student_record->save();
}
/**
* Load more records
*
* @param StudentRecord $student_record
* @return StudentRecord
*/
public function loadFeeData(StudentRecord $student_record) {
return $student_record->load('academicSession', 'student', 'student.parent', 'studentFeeRecords', 'batch', 'batch.course', 'batch.course.courseGroup', 'admission', 'studentFeeRecords.transportCircle', 'studentFeeRecords.feeConcession', 'studentFeeRecords.feeConcession.feeConcessionDetails', 'studentFeeRecords.studentOptionalFeeRecords', 'studentFeeRecords.transactions', 'feeAllocation', 'feeAllocation.feeAllocationGroups', 'feeAllocation.feeAllocationGroups.feeGroup', 'feeAllocation.feeAllocationGroups.feeGroup.feeHeads', 'feeAllocation.feeAllocationGroups.feeInstallments', 'feeAllocation.feeAllocationGroups.feeInstallments.transportFee', 'feeAllocation.feeAllocationGroups.feeInstallments.transportFee.transportFeeDetails', 'feeAllocation.feeAllocationGroups.feeInstallments.feeInstallmentDetails', 'feeAllocation.feeAllocationGroups.feeInstallments.feeInstallmentDetails.feeHead');
}
/**
* Get data for create fee
*
* @param StudentRecord $student_record
* @return Array
*/
public function getDataForCreateFee(StudentRecord $student_record) {
$student_record->load('academicSession', 'student', 'student.parent', 'studentFeeRecords', 'batch', 'batch.course', 'batch.course.courseGroup', 'admission');
$transport_circles = $this->transport_circle->filterBySession($student_record->academic_session_id)->get(['name', 'id']);
$fee_concessions = $this->fee_concession->filterBySession($student_record->academic_session_id)->get(['name', 'id']);
return compact('student_record', 'transport_circles', 'fee_concessions');
}
/**
* Create fee record for student
*
* @param StudentRecord $student_record
* @param Array $params
* @return void
*/
public function create(StudentRecord $student_record, $params) {
$batch = $this->batch->findOrFail($student_record->batch_id);
$fee_allocation = $this->fee_allocation->with('feeAllocationGroups', 'feeAllocationGroups.feeInstallments')->filterBySession()->where(function ($q) use ($batch) {
$q->where('batch_id', $batch->id)->orWhere('course_id', $batch->course_id);
})->first();
if (!$fee_allocation) {
throw ValidationException::withMessages(['batch_id' => trans('finance.no_fee_allocated')]);
}
$transport_circle_id = gv($params, 'transport_circle_id');
if ($transport_circle_id && !$this->transport_circle->find($transport_circle_id)) {
throw ValidationException::withMessages(['transport_circle_id' => trans('transport.could_not_find_circle')]);
}
$fee_concession_id = gv($params, 'fee_concession_id');
if ($fee_concession_id && !$this->fee_concession->find($fee_concession_id)) {
throw ValidationException::withMessages(['fee_concession_id' => trans('finance.could_not_find_fee_concession')]);
}
$existing_student_fee_record_count = $this->student_fee_record->whereStudentRecordId($student_record->id)->count();
if ($existing_student_fee_record_count) {
throw ValidationException::withMessages(['message' => trans('student.duplicate_fee_installment_found')]);
}
$installments = array();
foreach ($fee_allocation->feeAllocationGroups as $fee_allocation_group) {
foreach ($fee_allocation_group->feeInstallments as $fee_installment) {
$installments[] = array(
'student_record_id' => $student_record->id,
'fee_installment_id' => $fee_installment->id,
'transport_circle_id' => $transport_circle_id ?: null,
'fee_concession_id' => $fee_concession_id ?: null,
'status' => 'unpaid',
);
}
}
$this->student_fee_record->insert($installments);
$student_record->fee_allocation_id = $fee_allocation->id;
$student_record->save();
}
/**
* Get fee detail.
*
* @param StudentRecord $student_record
* @return Array
*/
public function fee(StudentRecord $student_record) {
if (!$student_record->fee_allocation_id) {
throw ValidationException::withMessages(['message' => trans('student.fee_unallocated')]);
}
$student_record = $this->loadFeeData($student_record);
$transport_circles = $this->transport_circle->filterBySession($student_record->academic_session_id)->get(['name', 'id']);
$fee_concessions = $this->fee_concession->filterBySession($student_record->academic_session_id)->get(['name', 'id']);
$late_fee_frequencies = getLateFeeFrequencies();
return compact('student_record', 'transport_circles', 'fee_concessions', 'late_fee_frequencies');
}
/**
* Get fee requisite.
*
* @return Array
*/
public function getFeePreRequisite() {
$accounts = $this->account->selectAllActive();
$payment_method_details = $this->payment_method->getAll();
$payment_methods = generateSelectOption($payment_method_details->pluck('name', 'id')->all());
return compact('accounts', 'payment_method_details', 'payment_methods');
}
/**
* Get transport fee
*
* @param StudentFeeRecord $student_fee_record
* @param FeeInstallment $fee_installment
* @return integer
*/
private function getTransportFee(StudentFeeRecord $student_fee_record, FeeInstallment $fee_installment) {
if ($fee_installment->feeAllocationGroup->feeGroup->getOption('has_transport') && $student_fee_record->transport_circle_id) {
$transport_fee = $fee_installment->transportFee ? $fee_installment->transportFee->transportFeeDetails->firstWhere('transport_circle_id', $student_fee_record->transport_circle_id) : null;
return $transport_fee ? $transport_fee->amount : 0;
}
return 0;
}
/**
* Get fee head amount
*
* @param StudentFeeRecord $student_fee_record
* @param FeeInstallmentDetail $fee_installment_detail
* @return integer
*/
private function getFee(StudentFeeRecord $student_fee_record, FeeInstallmentDetail $fee_installment_detail) {
$amount = $fee_installment_detail->amount;
if ($student_fee_record->studentOptionalFeeRecords->where('fee_head_id', $fee_installment_detail->fee_head_id)->count()) {
$amount = 0;
}
if ($amount && $student_fee_record->fee_concession_id) {
$fee_concession = $student_fee_record->feeConcession->feeConcessionDetails->firstWhere('fee_head_id', $fee_installment_detail->fee_head_id);
$concession = $fee_concession ? ($fee_concession->type == 'percent' ? (($amount * $fee_concession->amount) / 100) : $fee_concession->amount) : 0;
$amount -= $concession;
$amount = ($amount < 0) ? 0 : $amount;
}
return $amount;
}
/**
* Get installment total fee
*
* @param StudentRecord $student_record
* @param FeeInstallment $fee_installment
* @return integer
*/
private function getInstallmentTotal(StudentRecord $student_record, FeeInstallment $fee_installment) {
$total = 0;
$student_fee_record = $student_record->studentFeeRecords->firstWhere('fee_installment_id', $fee_installment->id);
foreach ($fee_installment->feeInstallmentDetails as $fee_installment_detail) {
$total += $this->getFee($student_fee_record, $fee_installment_detail);
}
$total += $this->getTransportFee($student_fee_record, $fee_installment);
return $total;
}
/**
* Get installment late fee
*
* @param StudentRecord $student_record
* @param FeeInstallment $fee_installment
* @param Date $date
* @return integer
*/
private function getLateFee(StudentRecord $student_record, FeeInstallment $fee_installment, $date = null) {
$date = ($date) ? toDate($date) : date('Y-m-d');
$student_fee_record = $student_record->studentFeeRecords->firstWhere('fee_installment_id', $fee_installment->id);
$due_date = $student_fee_record->due_date ? toDate($student_fee_record->due_date) : toDate($fee_installment->due_date);
$late_fee_applicable = (($student_fee_record->late_fee_applicable == null && $fee_installment->late_fee_applicable) || $student_fee_record->late_fee_applicable) ? 1 : 0;
if ($due_date < $date && $late_fee_applicable) {
$late_days = dateDiff($due_date, $date);
$per_period = floor($late_days / ($student_fee_record->late_fee_frequency ?: $fee_installment->late_fee_frequency));
$late_fee = ($student_fee_record->late_fee ?: $fee_installment->late_fee) * $per_period;
return $late_fee;
}
return 0;
}
public function getFeeInstallment(StudentRecord $student_record, $fee_installment_id) {
$fee_installment = $this->fee_installment->with('feeAllocationGroup', 'feeAllocationGroup.feeGroup', 'feeAllocationGroup.feeInstallments', 'feeAllocationGroup.feeInstallments.feeInstallmentDetails', 'transportFee', 'transportFee.transportFeeDetails')->whereHas('feeAllocationGroup', function ($q) use ($student_record) {
$q->whereHas('feeAllocation', function ($q1) use ($student_record) {
$q1->where('batch_id', $student_record->batch_id)->orWhere('course_id', $student_record->batch->course_id);
});
})->filterById($fee_installment_id)->first();
if (!$fee_installment) {
throw ValidationException::withMessages(['message' => trans('finance.could_not_find_fee_installment')]);
}
return $fee_installment;
}
private function validateAmount($amount) {
if ($amount < 0) {
rollBackTransaction();
throw ValidationException::withMessages(['message' => trans('general.transaction_failed')]);
}
}
private function validateIntegerMinZero($number, $name, $field = 'message') {
if (!is_numeric($number)) {
throw ValidationException::withMessages([$field => trans('validation.numeric', ['attribute' => $name])]);
}
if ($number < 0) {
throw ValidationException::withMessages([$field => trans('validation.min.numeric', ['attribute' => $name, 'min' => 0])]);
}
}
private function validatePreviousPaymentDate(StudentRecord $student_record, $fee_installment, $params = array()) {
$date = toDate(gv($params, 'date'));
$previous_fee_paid_ids = $this->student_fee_record->filterByStudentRecordId($student_record->id)->whereIn('status', ['paid', 'partially_paid'])
->whereHas('feeInstallment', function ($q) use ($fee_installment) {
$q->where('fee_allocation_group_id', $fee_installment->fee_allocation_group_id);
})->get()->pluck('id')->all();
$previous_paid_date = $this->transaction->whereIn('student_fee_record_id', $previous_fee_paid_ids)->where('is_cancelled', 0)->max('date');
if ($previous_paid_date > $date) {
throw ValidationException::withMessages(['message' => trans('student.date_cannot_less_than_previous_paid_date', ['date' => showDate($previous_paid_date)])]);
}
}
private function validateInput($fee_installments, $params = array()) {
$installments = gv($params, 'installments', []);
$date = toDate(gv($params, 'date'));
$amount = gv($params, 'amount', 0);
$additional_fee_charge = gv($params, 'additional_fee_charge', 0);
$additional_fee_discount = gv($params, 'additional_fee_discount', 0);
if ($additional_fee_charge && ! gv($params, 'additional_fee_charge_label')) {
throw ValidationException::withMessages(['additional_fee_charge_label' => trans('validation.required', ['attribute' => trans('student.additional_fee_charge')])]);
}
if ($additional_fee_discount && ! gv($params, 'additional_fee_discount_label')) {
throw ValidationException::withMessages(['additional_fee_discount_label' => trans('validation.required', ['attribute' => trans('student.additional_fee_discount')])]);
}
if (!count($installments)) {
throw ValidationException::withMessages(['message' => trans('finance.installment_missing')]);
}
$can_customize_fee_date = (\Auth::check() && \Auth::user()->can('customize-fee-date')) ? true : false;
if (!$can_customize_fee_date && $date != date('Y-m-d')) {
throw ValidationException::withMessages(['message' => trans('student.fee_payment_date_cannot_be_customized')]);
}
$this->validateIntegerMinZero($amount, trans('finance.amount'));
$previous_installment = null;
$total = 0;
foreach ($installments as $installment) {
$this->validateIntegerMinZero(gv($installment, 'installment_balance', 0), trans('finance.installment_balance'));
$this->validateIntegerMinZero(gv($installment, 'late_fee_balance', 0), trans('finance.late_fee_balance'));
$installment_id = gv($installment, 'fee_installment_id');
$student_fee_installment = $fee_installments->firstWhere('id', $installment_id);
if (!$student_fee_installment) {
throw ValidationException::withMessages(['message' => trans('finance.could_not_find_fee_installment')]);
}
if ($previous_installment && toDate($previous_installment->due_date) > toDate($student_fee_installment->due_date)) {
throw ValidationException::withMessages(['message' => trans('general.invalid_input')]);
}
$previous_installment = $student_fee_installment;
$total += (gv($installment, 'installment_balance', 0) + gv($installment, 'late_fee_balance', 0));
}
$can_make_partial_payment = (\Auth::check() && \Auth::user()->can('make-partial-fee-payment')) ? true : false;
if (!$can_make_partial_payment && $total != $amount) {
throw ValidationException::withMessages(['message' => trans('finance.total_mismatch')]);
}
$final_amount = $amount + $additional_fee_charge - $additional_fee_discount;
if ($amount < 0) {
throw ValidationException::withMessages(['message' => trans('validation.min.numeric', ['attribute' => trans('finance.amount'), 'min' => 0])]);
}
}
private function initializeTransaction($params = array()) {
$date = toDate(gv($params, 'date'));
$amount = gv($params, 'amount', 0);
$is_online_payment = gbv($params, 'is_online_payment');
$account_id = gv($params, 'account_id');
$payment_method_id = gv($params, 'payment_method_id');
$remarks = gv($params, 'remarks');
$source = gv($params, 'source');
$source_detail = gv($params, 'source_detail');
$gateway_token = gv($params, 'gateway_token');
$account_prefix = substr(strtoupper($source), 0, 3);
$installments = gv($params, 'installments', []);
if (!$is_online_payment && $amount) {
$account = $this->account->findOrFail($account_id, 'account_id');
$account_prefix = $account->prefix;
$payment_method = $this->payment_method->findOrFail($payment_method_id, 'payment_method_id');
$number = $this->transaction->filterByAccountId($account->id)->filterByType(1)->max('number');
} else {
$number = $this->transaction->whereSource($source)->max('number');
}
$number = ($number) ?: 0;
$instrument_number = (isset($payment_method) && $payment_method->getOption('requires_instrument_number')) ? gv($params, 'instrument_number') : null;
$instrument_date = (isset($payment_method) && $payment_method->getOption('requires_instrument_date')) ? toDate(gv($params, 'instrument_date')) : null;
$instrument_clearing_date = (isset($payment_method) && $payment_method->getOption('requires_instrument_clearing_date')) ? toDate(gv($params, 'instrument_clearing_date')) : null;
$instrument_bank_detail = (isset($payment_method) && $payment_method->getOption('requires_instrument_bank_detail')) ? gv($params, 'instrument_bank_detail') : null;
$reference_number = ($is_online_payment || (isset($payment_method) && $payment_method->getOption('requires_instrument_bank_detail'))) ? gv($params, 'reference_number') : null;
$transaction = [
'user_id' => gv($params, 'user_id') ?: (\Auth::check() ? \Auth::user()->id : null),
'prefix' => $account_prefix,
'account_id' => $account_id,
'date' => toDate($date),
'remarks' => $remarks,
'payment_method_id' => $payment_method_id,
'is_multi_installment' => count($installments) > 1 ? 1 : 0,
'instrument_number' => $instrument_number,
'instrument_clearing_date' => $instrument_clearing_date,
'instrument_bank_detail' => $instrument_bank_detail,
'instrument_date' => $instrument_date,
'reference_number' => $reference_number,
'source' => $source,
'source_detail' => $source_detail,
'gateway_token' => $gateway_token,
'is_online_payment' => $is_online_payment,
];
return compact('transaction', 'number');
}
/**
* Make fee payment.
*
* @param StudentRecord $student_record
* @return Array $params
*/
public function makePayment(StudentRecord $student_record, $params = array()) {
$student_record = $this->loadFeeData($student_record);
$fee_installment_id = gv($params, 'installment_id');
$date = toDate(gv($params, 'date'));
$amount = gv($params, 'amount', 0);
$handling_fee = gv($params, 'handling_fee', 0);
$installments = gv($params, 'installments', []);
$is_student_or_parent = \Auth::user()->hasAnyRole([config('system.default_role.student'), config('system.default_role.parent')]) ? true : false;
if (! $is_student_or_parent) {
$amount -= gv($params, 'additional_fee_charge', 0);
$amount += gv($params, 'additional_fee_discount', 0);
$params['amount'] = $amount;
}
$data = $this->initializeTransaction($params);
$transaction = $data['transaction'];
$number = $data['number'];
$transaction_group_id = null;
$fee_installment = $this->getFeeInstallment($student_record, $fee_installment_id);
$fee_installments = $fee_installment->feeAllocationGroup->feeInstallments->sortBy('due_date');
$this->validateInput($fee_installments, $params);
$this->validatePreviousPaymentDate($student_record, $fee_installment, $params);
$can_customize_late_fee = (\Auth::check() && \Auth::user()->can('customize-late-fee')) ? true : false;
beginTransaction();
foreach ($installments as $index => $installment) {
$installment_id = gv($installment, 'fee_installment_id');
$student_fee_installment = $fee_installments->firstWhere('id', $installment_id);
$student_fee_record = $student_record->studentFeeRecords->firstWhere('fee_installment_id', $installment_id);
if (!$student_fee_record) {
throw ValidationException::withMessages(['message' => trans('finance.could_not_find_fee_concession')]);
}
$fee = $this->getInstallmentTotal($student_record, $student_fee_installment);
$late_fee = ($fee) ? $this->getLateFee($student_record, $student_fee_installment, $date) : 0;
$paid = 0;
foreach ($student_fee_record->transactions->where('is_cancelled', 0)->all() as $paid_fee) {
$transaction_additional_fee_charge = $paid_fee->getOption('additional_fee_charge');
$transaction_additional_fee_discount = $paid_fee->getOption('additional_fee_discount');
$fee += gv($transaction_additional_fee_charge, 'amount', 0) - gv($transaction_additional_fee_discount, 'amount', 0);
$paid += $paid_fee->amount;
}
$transaction['student_fee_record_id'] = $student_fee_record->id;
$transport_fee = $this->getTransportFee($student_fee_record, $student_fee_installment);
$input_installment_balance = gv($installment, 'installment_balance', 0);
$installment_balance = ($fee > $paid) ? ($fee - $paid) : 0;
if ($installment_balance != $input_installment_balance) {
throw ValidationException::withMessages(['message' => trans('finance.total_mismatch')]);
}
$input_late_fee_balance = gv($installment, 'late_fee_balance', 0);
$late_fee_balance = (!$installment_balance && $late_fee) ? ($late_fee - ($paid - $fee)) : $late_fee;
if (!$can_customize_late_fee && $late_fee_balance != $input_late_fee_balance) {
throw ValidationException::withMessages(['message' => trans('finance.total_mismatch')]);
}
$is_customized_late_fee = 0;
if ($can_customize_late_fee && $late_fee_balance != $input_late_fee_balance) {
$late_fee_balance = $input_late_fee_balance;
$is_customized_late_fee = 1;
}
$balance = $installment_balance + $late_fee_balance;
if (!$index && !$amount && $balance) {
throw ValidationException::withMessages(['message' => trans('finance.cannot_process_if_amount_is_zero')]);
}
$is_payable = 0;
$is_paid = 0;
if ($student_fee_record->status != 'paid' && $amount > 0) {
$is_paid = ($amount >= $balance) ? 1 : 0;
$transaction_amount = ($amount > $balance) ? $balance : $amount;
$amount -= $transaction_amount;
$is_payable = 1;
}
$this->validateAmount($amount);
if ($is_payable) {
$number++;
$transaction['number'] = $number;
$transaction['amount'] = $transaction_amount;
$transaction['transaction_group_id'] = $transaction_group_id;
$transport_fee_paid = 0;
foreach ($student_fee_record->transactions->where('is_cancelled', 0)->all() as $paid_transport) {
$transport_fee_paid += ($paid_transport->getOption('transport_fee') ?: 0);
}
$late_fee_paid = 0;
foreach ($student_fee_record->transactions->where('is_cancelled', 0)->all() as $paid_late) {
$late_fee_paid += ($paid_late->getOption('late_fee') ?: 0);
}
$txn = $this->createFeeTransaction($transaction);
$transaction_amount = $this->createStudentFeeRecordDetail($student_fee_record, $student_fee_installment, $transaction_amount, $txn->id);
$transport_fee_balance = $transport_fee - $transport_fee_paid;
$transport = ($transaction_amount) ? (($transaction_amount > $transport_fee_balance) ? $transport_fee_balance : $transaction_amount) : 0;
$transaction_amount -= $transport;
$transport_fee_balance -= $transport;
if ($is_customized_late_fee && $transaction_amount < $late_fee_balance) {
throw ValidationException::withMessages(['message' => trans('finance.customize_late_fee_must_be_charged_at_one_time')]);
}
$late = ($transaction_amount) ? (($transaction_amount > $late_fee_balance) ? $late_fee_balance : $transaction_amount) : 0;
$transaction_amount -= $late;
$txn_options = $txn->options;
$txn_options = [
'transport_fee' => $transport,
'late_fee' => $late,
];
if (!$transaction_group_id && $handling_fee) {
$txn->handling_fee = $handling_fee;
}
if (!$transaction_group_id && !$is_student_or_parent) {
$txn_options['additional_fee_charge'] = array(
'label' => gv($params, 'additional_fee_charge_label'),
'amount' => gv($params, 'additional_fee_charge', 0)
);
$txn_options['additional_fee_discount'] = array(
'label' => gv($params, 'additional_fee_discount_label'),
'amount' => gv($params, 'additional_fee_discount', 0)
);
$txn->amount = $txn->amount + gv($params, 'additional_fee_charge', 0) - gv($params, 'additional_fee_discount', 0);
}
if (!$transaction_group_id && $transaction['is_multi_installment']) {
$transaction_group_id = $txn->id;
$txn->transaction_group_id = $transaction_group_id;
}
$txn->options = $txn_options;
$txn->save();
$student_fee_record->status = $is_paid ? 'paid' : 'partially_paid';
$student_fee_record->transport_fee = $student_fee_record->transport_fee + $transport;
$student_fee_record->late_fee_charged = $student_fee_record->late_fee_charged + $late;
$student_fee_record->save();
}
if (!$is_payable && !$amount && !$balance) {
$student_fee_record->status = 'paid';
$student_fee_record->save();
}
}
if ($amount) {
$balance = currency(gv($params, 'amount') - $amount, 1);
rollBackTransaction();
throw ValidationException::withMessages(['message' => trans('finance.amount_greater_than_balance', ['balance' => $balance, 'extra' => $amount])]);
}
commitTransaction();
}
private function createStudentFeeRecordDetail(StudentFeeRecord $student_fee_record, $installment, $amount, $transaction_id) {
$student_fee_record_details = $this->student_fee_record_detail->whereHas('transaction', function ($q) {
$q->where('is_cancelled', 0);
})->filterByStudentFeeRecordId($student_fee_record->id)->get();
foreach ($installment->feeInstallmentDetails as $fee_installment_detail) {
$fee_head_amount = $this->getFee($student_fee_record, $fee_installment_detail);
$balance = $fee_head_amount;
foreach ($student_fee_record_details->where('fee_head_id', $fee_installment_detail->fee_head_id)->all() as $paid_fee) {
$balance -= $paid_fee->amount;
}
// if ($balance) {
$fee_amount = ($amount > $balance) ? $balance : $amount;
$this->student_fee_record_detail->forceCreate([
'student_fee_record_id' => $student_fee_record->id,
'fee_head_id' => $fee_installment_detail->fee_head_id,
'amount' => $fee_amount,
'transaction_id' => $transaction_id,
'options' => [],
]);
$amount -= $fee_amount;
// }
$this->validateAmount($amount);
}
return $amount;
}
private function createFeeTransaction($params = array()) {
$transaction_group_id = gv($params, 'transaction_group_id');
$transaction = $this->transaction->forceCreate([
'uuid' => Str::uuid(),
'type' => 1,
'prefix' => gv($params, 'prefix'),
'number' => gv($params, 'number'),
'user_id' => gv($params, 'user_id'),
'amount' => gv($params, 'amount', 0),
'account_id' => gv($params, 'account_id'),
'head' => 'fee',
'student_fee_record_id' => gv($params, 'student_fee_record_id'),
'date' => toDate(gv($params, 'date')),
'transaction_group_id' => $transaction_group_id,
'remarks' => gv($params, 'remarks'),
'upload_token' => Str::uuid(),
'payment_method_id' => gv($params, 'payment_method_id'),
'instrument_number' => gv($params, 'instrument_number'),
'instrument_date' => gv($params, 'instrument_date'),
'instrument_clearing_date' => gv($params, 'instrument_clearing_date'),
'instrument_bank_detail' => gv($params, 'instrument_bank_detail'),
'reference_number' => gv($params, 'reference_number'),
'source' => gv($params, 'source'),
'source_detail' => gv($params, 'source_detail'),
'gateway_token' => gv($params, 'gateway_token'),
'is_online_payment' => gbv($params, 'is_online_payment'),
'options' => [],
]);
if (!$transaction_group_id) {
$transaction_group_id = $transaction->id;
$transaction->transaction_group_id = $transaction_group_id;
$transaction->save();
}
return $transaction;
}
/**
* Get Student Fee Record.
*
* @param StudentRecord $student_record
* @param integer $student_fee_record_id
* @return StudentFeeRecord
*/
private function getStudentFeeRecord(StudentRecord $student_record, $fee_record_id) {
$student_fee_record = $this->student_fee_record->with('feeInstallment')->filterByStudentRecordId($student_record->id)->filterById($fee_record_id)->first();
if (!$student_fee_record) {
throw ValidationException::withMessages(['message' => trans('general.invalid_link')]);
}
return $student_fee_record;
}
/**
* Get fee receipt detail.
*
* @param StudentRecord $student_record
* @param integer $student_fee_record_id
* @param integer $transaction_id
* @return Transaction $transaction
*/
public function getReceipt(StudentRecord $student_record, $fee_record_id, $transaction_id) {
$student_fee_record = $this->getStudentFeeRecord($student_record, $fee_record_id);
$transaction = $this->transaction->with('account', 'paymentMethod', 'user', 'user.employee', 'studentFeeRecord', 'studentFeeRecord.feeInstallment', 'studentFeeRecord.studentFeeRecordDetails', 'studentFeeRecord.studentFeeRecordDetails.feeHead', 'studentFeeRecordDetails', 'studentFeeRecordDetails.feeHead')->filterById($transaction_id)->whereStudentFeeRecordId($student_fee_record->id)->where('is_cancelled', 0)->first();
if (!$transaction) {
throw ValidationException::withMessages(['message' => trans('general.could_not_find_record')]);
}
return $transaction;
}
/**
* Get fee payment detail.
*
* @param StudentRecord $student_record
* @param integer $student_fee_record_id
* @return Transaction $transaction
*/
public function getPaymentDetail(StudentRecord $student_record, $fee_record_id) {
$student_fee_record = $this->getStudentFeeRecord($student_record, $fee_record_id);
$student_fee_records = $this->student_fee_record->where('student_record_id', $student_record->id)->whereHas('feeInstallment', function ($q) use ($student_fee_record) {
$q->where('fee_allocation_group_id', $student_fee_record->feeInstallment->fee_allocation_group_id);
})->get()->pluck('id')->all();
$transactions = $this->transaction->with(['account', 'paymentMethod', 'user', 'user.employee', 'transactionGroups' => function ($q) {
$q->where('is_cancelled', 0);
}])->where('student_fee_record_id', $fee_record_id)->where('is_cancelled', 0)->get();
foreach ($transactions as $transaction) {
$transaction->is_deletable = $this->transaction->whereIn('student_fee_record_id', $student_fee_records)->whereNotIn('id', $transaction->transactionGroups->pluck('id')->all())->where('id', '>', $transaction->id)->where('is_cancelled', 0)->count() ? 0 : 1;
$group = $this->transaction->with(['transactionGroups' => function ($q) {
$q->where('is_cancelled', 0);
}])->filterById($transaction->transaction_group_id)->first();
$transaction->groups = $group->transactionGroups;
}
return compact('transactions');
}
/**
* Cancel empty fee payment.
*
* @param StudentRecord $student_record
* @param integer $student_fee_record_id
* @return null
*/
public function cancelEmptyPayment(StudentRecord $student_record, $fee_record_id) {
$student_fee_record = $this->getStudentFeeRecord($student_record, $fee_record_id);
$paid = $this->student_fee_record->where('id', '!=', $student_fee_record->id)->where('student_record_id', $student_record->id)->whereHas('feeInstallment', function ($q) use ($student_fee_record) {
$q->where('fee_allocation_group_id', $student_fee_record->feeInstallment->fee_allocation_group_id)->where('due_date', '>=', toDate($student_fee_record->feeInstallment->due_date));
})->whereIn('status', ['paid', 'partially_paid'])->count();
if ($paid) {
throw ValidationException::withMessages(['message' => trans('finance.last_fee_payment_can_only_be_cancelled')]);
}
$student_fee_record->status = 'unpaid';
$student_fee_record->save();
}
/**
* Cancel fee payment.
*
* @param StudentRecord $student_record
* @param integer $student_fee_record_id
* @param integer $transaction_id
* @param Arrau $params
* @return null
*/
public function cancelPayment(StudentRecord $student_record, $fee_record_id, $transaction_id, $params) {
$student_fee_record = $this->getStudentFeeRecord($student_record, $fee_record_id);
$transaction = $this->transaction->with(['transactionGroups' => function ($q) {
$q->where('is_cancelled', 0);
}])->where('student_fee_record_id', $fee_record_id)->filterById($transaction_id)->whereIsCancelled(0)->first();
if (!$transaction) {
throw ValidationException::withMessages(['message' => trans('general.could_not_find_record')]);
}
if ($transaction->is_online_payment) {
throw ValidationException::withMessages(['message' => trans('finance.could_not_cancel_online_payment')]);
}
if (!$this->employee->userAccessible($transaction->User->Employee) && \Auth::user()->id != $transaction->user_id) {
throw ValidationException::withMessages(['message' => trans('user.permission_denied')]);
}
$student_fee_records = $this->student_fee_record->where('student_record_id', $student_record->id)->whereHas('feeInstallment', function ($q) use ($student_fee_record) {
$q->where('fee_allocation_group_id', $student_fee_record->feeInstallment->fee_allocation_group_id);
})->get()->pluck('id')->all();
$is_deletable = $this->transaction->whereIn('student_fee_record_id', $student_fee_records)->whereNotIn('id', $transaction->transactionGroups->pluck('id')->all())->where('id', '>', $transaction->id)->where('is_cancelled', 0)->count() ? 0 : 1;
if (!$is_deletable) {
throw ValidationException::withMessages(['message' => trans('finance.last_fee_payment_can_only_be_cancelled')]);
}
$transaction_group = $this->transaction->with(['transactionGroups' => function ($q) {
$q->where('is_cancelled', 0);
}])->filterById($transaction->transaction_group_id)->first();
$transaction_group_ids = $transaction_group->transactionGroups->pluck('id')->all();
$transactions = $this->transaction->whereIn('id', $transaction_group_ids)->with('studentFeeRecord', 'studentFeeRecord.studentFeeRecordDetails', 'studentFeeRecord.studentFeeRecordDetails.transaction')->get();
beginTransaction();
foreach ($transactions as $transaction) {
if ($transaction->is_online_payment) {
throw ValidationException::withMessages(['message' => trans('finance.could_not_cancel_online_payment')]);
}
$transaction->update(['is_cancelled' => 1, 'cancelled_at' => now(), 'cancellation_remarks' => gv($params, 'cancellation_remarks')]);
$student_fee_record = $transaction->studentFeeRecord;
$student_fee_record->transport_fee -= ($transaction->getOption('transport_fee') ?: 0);
$student_fee_record->late_fee_charged -= ($transaction->getOption('late_fee') ?: 0);
if ($student_fee_record->transport_fee < 0) {
throw ValidationException::withMessages(['message' => trans('finance.could_not_cancel_selected_receipt')]);
}
if ($student_fee_record->late_fee_charged < 0) {
throw ValidationException::withMessages(['message' => trans('finance.could_not_cancel_selected_receipt')]);
}
$paid = $student_fee_record->transport_fee + $student_fee_record->late_fee_charged;
foreach ($student_fee_record->studentFeeRecordDetails->where('transaction_id', '!=', null)->all() as $student_fee_record_detail) {
if (!$student_fee_record_detail->transaction->is_cancelled && !in_array($student_fee_record_detail->transaction_id, $transaction_group_ids)) {
$paid += $student_fee_record_detail->amount;
}
}
$student_fee_record->status = ($paid) ? 'partially_paid' : 'unpaid';
$student_fee_record->save();
}
commitTransaction();
}
/**
* Get id card pre requisite.
*
* @return Array
*/
public function getIdCardPreRequisite() {
$batches = $this->course_group->getBatchOption();
$id_card_templates = $this->id_card_template->selectAllByType('student');
return compact('batches', 'id_card_templates');
}
/**
* Validate Id card template
* @param integer $id_card_template_id
* @return IdCardTemplate
*/
public function validateIdCardTemplate($id_card_template_id) {
$id_card_template = $this->id_card_template->findOrFail($id_card_template_id);
if ($id_card_template->type != 'student') {
throw ValidationException::withMessages(['message' => trans('general.invalid_action')]);
}
return $id_card_template;
}
/**
* Get roll number pre requisite.
*
* @return Array
*/
public function getRollNumberPreRequisite() {
$batches = $this->course_group->getBatchOption();
return compact('batches');
}
/**
* Fetch students for given batch
*
* @param Array $params
* @return Array $student_records
*/
public function fetchBatchWiseStudent($params = array()) {
$batch_id = gv($params, 'batch_id');
$batch = $this->batch->findOrFail($batch_id);
$student_records = $this->student_record->with('student', 'student.parent', 'admission')->filterBySession()->filterByBatchId($batch_id)->whereNull('date_of_exit')->select('student_records.*', \DB::raw('(SELECT concat_ws(" ", first_name,middle_name,last_name) FROM students WHERE student_records.student_id = students.id ) as name'))->orderBy('name','asc')->get();
return compact('student_records', 'batch');
}
/**
* Fetch students for given batch for login
*
* @param Array $params
* @return Array $student_records
*/
public function fetchBatchWiseStudentForLogin($params = array()) {
$batch_id = gv($params, 'batch_id');
$batch = $this->batch->findOrFail($batch_id);
$student_records = $this->student_record->with('student','student.user', 'student.parent','student.parent.user')->filterBySession()->filterByBatchId($batch_id)->whereNull('date_of_exit')->select('student_records.*', \DB::raw('(SELECT concat_ws(" ", first_name,middle_name,last_name) FROM students WHERE student_records.student_id = students.id ) as name'))->orderBy('name','asc')->get();
return compact('student_records', 'batch');
}
/**
* Store roll number of students of given batch
*
* @param Array $params
* @return null
*/
public function storeRollNumber($params = array()) {
$batch_id = gv($params, 'batch_id');
$batch = $this->batch->findOrFail($batch_id);
$students = gv($params, 'students', []);
if (!$students) {
throw ValidationException::withMessages(['message' => trans('student.could_not_find')]);
}
$student_record_ids = $this->student_record->with('student', 'student.parent', 'admission')->filterBySession()->filterByBatchId($batch_id)->whereNull('date_of_exit')->get()->pluck('id')->all();
$roll_numbers = array();
foreach ($students as $student) {
$roll_numbers[] = gv($student, 'roll_number');
}
if (count($roll_numbers) > count(array_unique($roll_numbers))) {
throw ValidationException::withMessages(['message' => trans('student.duplicate_roll_number_found')]);
}
foreach ($students as $index => $student) {
$student_record_id = gv($student, 'id');
if (!in_array($student_record_id, $student_record_ids)) {
throw ValidationException::withMessages(['message' => trans('student.could_not_find')]);
}
$roll_number = gv($student, 'roll_number');
if (!$roll_number) {
throw ValidationException::withMessages([$index . '_roll_number' => trans('validation.required', ['attribute' => trans('student.roll_number')])]);
}
$this->student_record->filterById($student_record_id)->update(['roll_number' => $roll_number]);
}
}
public function search($q) {
if (!\Auth::user()->can('list-student')) {
return [];
}
$query = $this->student_record->select('id', 'student_id', 'batch_id', 'admission_id', 'roll_number')
->with([
'student:id,uuid,student_parent_id,first_name,middle_name,last_name,contact_number,date_of_birth,gender,student_photo',
'student.parent:id,first_guardian_name',
'batch:id,course_id,name,options',
'batch.course:id,name',
'admission:id,number,prefix',
])->where(function ($q1) use ($q) {
$q1->whereHas('student', function ($q2) use ($q) {
$q2->where(\DB::raw('(SELECT concat_ws(" ", first_name,middle_name,last_name))'), 'LIKE', '%' . $q . '%');
})->orWhereHas('admission', function ($q3) use ($q) {
$q3->where(\DB::raw('concat_ws(prefix," ",LPAD(number, ' . config('config.admission_number_digit') . ', 0))'), 'LIKE', '%' . $q . '%');
});
})->filterBySession()->whereNull('date_of_exit');
if (\Auth::user()->hasRole(config('system.default_role.student'))) {
$query->whereHas('student', function ($q4) {
$q4->filterById(\Auth::user()->Student->id);
});
}
if (\Auth::user()->hasRole(config('system.default_role.parent'))) {
$query->whereHas('student', function ($q5) {
$q5->whereIn('id', \Auth::user()->Parent->Students->pluck('id')->all());
});
}
return $query->take(10)->get();
}
}