Initial financial project import
This commit is contained in:
@@ -0,0 +1,704 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/db.php';
|
||||
require_once __DIR__ . '/account_service.php';
|
||||
require_once __DIR__ . '/card_billing_service.php';
|
||||
|
||||
function split_amount_evenly(float $amount, int $months): array
|
||||
{
|
||||
if ($months <= 0) {
|
||||
throw new RuntimeException('개월 수가 올바르지 않습니다.');
|
||||
}
|
||||
|
||||
// 원화 기준: 소수점 제거
|
||||
$amount = (int)floor($amount);
|
||||
|
||||
$base = intdiv($amount, $months);
|
||||
$remainder = $amount % $months;
|
||||
|
||||
$amounts = array_fill(0, $months, $base);
|
||||
|
||||
// 남는 원 단위는 마지막 회차에 몰아줌
|
||||
if ($remainder > 0) {
|
||||
$amounts[$months - 1] += $remainder;
|
||||
}
|
||||
|
||||
return $amounts;
|
||||
}
|
||||
|
||||
function calculate_installment_interest_total(
|
||||
float $principalAmount,
|
||||
int $installmentMonths,
|
||||
float $annualInterestRate
|
||||
): float {
|
||||
if ($installmentMonths <= 1 || $annualInterestRate <= 0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
$principalAmount = floor($principalAmount);
|
||||
$monthlyRate = ($annualInterestRate / 100.0) / 12.0;
|
||||
|
||||
$averageOutstanding = $principalAmount / 2.0;
|
||||
$interestTotal = $averageOutstanding * $monthlyRate * $installmentMonths;
|
||||
|
||||
// 원화 기준 버림
|
||||
return (float)floor($interestTotal);
|
||||
}
|
||||
|
||||
function create_installment_schedule(
|
||||
int $userId,
|
||||
int $transactionId,
|
||||
int $accountId,
|
||||
float $principalAmount,
|
||||
int $installmentMonths,
|
||||
string $transactionDate,
|
||||
float $annualInterestRate = 0.0,
|
||||
?float $interestTotal = null,
|
||||
?float $totalBilledAmount = null,
|
||||
string $interestType = 'none'
|
||||
): void {
|
||||
$pdo = db();
|
||||
|
||||
if ($installmentMonths <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 원화 기준
|
||||
$principalAmount = (float)floor($principalAmount);
|
||||
$annualInterestRate = round($annualInterestRate, 4);
|
||||
|
||||
if ($interestTotal === null) {
|
||||
$interestTotal = calculate_installment_interest_total(
|
||||
$principalAmount,
|
||||
$installmentMonths,
|
||||
$annualInterestRate
|
||||
);
|
||||
}
|
||||
|
||||
$interestTotal = (float)floor($interestTotal);
|
||||
|
||||
if ($totalBilledAmount === null) {
|
||||
$totalBilledAmount = $principalAmount + $interestTotal;
|
||||
}
|
||||
|
||||
$totalBilledAmount = (float)floor($totalBilledAmount);
|
||||
|
||||
if ($totalBilledAmount < $principalAmount) {
|
||||
throw new RuntimeException('총 청구금액은 원금보다 작을 수 없습니다.');
|
||||
}
|
||||
|
||||
if (($principalAmount + $interestTotal) !== $totalBilledAmount) {
|
||||
throw new RuntimeException('원금 + 총이자와 총 청구금액이 일치해야 합니다.');
|
||||
}
|
||||
|
||||
$pdo->beginTransaction();
|
||||
|
||||
try {
|
||||
$stmtAcc = $pdo->prepare("
|
||||
SELECT *
|
||||
FROM accounts
|
||||
WHERE id = ?
|
||||
AND user_id = ?
|
||||
LIMIT 1
|
||||
");
|
||||
$stmtAcc->execute([$accountId, $userId]);
|
||||
$account = $stmtAcc->fetch();
|
||||
|
||||
/*
|
||||
* 핵심:
|
||||
* 1회차 시작월은 거래월이 아니라
|
||||
* 카드사 신용공여기간 계산 결과인 billing_year_month 기준.
|
||||
*
|
||||
* 예:
|
||||
* 2026-04-24 사용 + 우리카드 25일 결제
|
||||
* => startYm = 2026-05
|
||||
* => 1회차 2026-05
|
||||
*/
|
||||
$startYm = null;
|
||||
|
||||
if ($account) {
|
||||
$startYm = get_card_billing_year_month($account, $transactionDate);
|
||||
}
|
||||
|
||||
if (!$startYm) {
|
||||
$startYm = date('Y-m', strtotime($transactionDate));
|
||||
}
|
||||
|
||||
$principalParts = split_amount_evenly($principalAmount, $installmentMonths);
|
||||
$interestParts = split_amount_evenly($interestTotal, $installmentMonths);
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO installments
|
||||
(
|
||||
user_id,
|
||||
transaction_id,
|
||||
account_id,
|
||||
principal_amount,
|
||||
interest_total,
|
||||
total_billed_amount,
|
||||
installment_months,
|
||||
annual_interest_rate,
|
||||
start_year_month,
|
||||
interest_type,
|
||||
current_cycle,
|
||||
is_completed,
|
||||
prepaid_principal_amount,
|
||||
prepaid_interest_amount
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, 0, 0, 0)
|
||||
");
|
||||
|
||||
$stmt->execute([
|
||||
$userId,
|
||||
$transactionId,
|
||||
$accountId,
|
||||
$principalAmount,
|
||||
$interestTotal,
|
||||
$totalBilledAmount,
|
||||
$installmentMonths,
|
||||
$annualInterestRate,
|
||||
$startYm,
|
||||
$annualInterestRate > 0 ? $interestType : 'none'
|
||||
]);
|
||||
|
||||
$installmentId = (int)$pdo->lastInsertId();
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO installment_schedules
|
||||
(
|
||||
installment_id,
|
||||
cycle_no,
|
||||
bill_year_month,
|
||||
principal_amount,
|
||||
interest_amount,
|
||||
total_amount,
|
||||
is_billed,
|
||||
billed_at
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
");
|
||||
|
||||
$currentYm = date('Y-m');
|
||||
|
||||
for ($i = 1; $i <= $installmentMonths; $i++) {
|
||||
$ym = date('Y-m', strtotime($startYm . '-01 +' . ($i - 1) . ' month'));
|
||||
|
||||
$principalPart = (float)$principalParts[$i - 1];
|
||||
$interestPart = (float)$interestParts[$i - 1];
|
||||
$totalPart = $principalPart + $interestPart;
|
||||
|
||||
// 과거 청구월은 자동 청구완료
|
||||
$isBilled = ($ym < $currentYm) ? 1 : 0;
|
||||
$billedAt = $isBilled ? date('Y-m-d H:i:s') : null;
|
||||
|
||||
$stmt->execute([
|
||||
$installmentId,
|
||||
$i,
|
||||
$ym,
|
||||
$principalPart,
|
||||
$interestPart,
|
||||
$totalPart,
|
||||
$isBilled,
|
||||
$billedAt
|
||||
]);
|
||||
}
|
||||
|
||||
recalculate_installment_status($installmentId);
|
||||
|
||||
$pdo->commit();
|
||||
} catch (Throwable $e) {
|
||||
$pdo->rollBack();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
function delete_installment_by_transaction_id(int $transactionId): void
|
||||
{
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare("DELETE FROM installments WHERE transaction_id = ?");
|
||||
$stmt->execute([$transactionId]);
|
||||
}
|
||||
|
||||
function get_installment_due_this_month(int $userId, string $yearMonth): float
|
||||
{
|
||||
$pdo = db();
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT COALESCE(SUM(s.total_amount), 0) AS total_due
|
||||
FROM installment_schedules s
|
||||
JOIN installments i ON i.id = s.installment_id
|
||||
WHERE i.user_id = ?
|
||||
AND s.bill_year_month = ?
|
||||
AND s.is_billed = 0
|
||||
");
|
||||
$stmt->execute([$userId, $yearMonth]);
|
||||
$row = $stmt->fetch();
|
||||
|
||||
return (float)($row['total_due'] ?? 0);
|
||||
}
|
||||
|
||||
function get_installment_remaining_principal(int $userId): float
|
||||
{
|
||||
$pdo = db();
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT COALESCE(SUM(s.principal_amount), 0) AS total_principal
|
||||
FROM installment_schedules s
|
||||
JOIN installments i ON i.id = s.installment_id
|
||||
WHERE i.user_id = ?
|
||||
AND s.is_billed = 0
|
||||
");
|
||||
$stmt->execute([$userId]);
|
||||
$row = $stmt->fetch();
|
||||
|
||||
return (float)($row['total_principal'] ?? 0);
|
||||
}
|
||||
|
||||
function get_installment_remaining_interest(int $userId): float
|
||||
{
|
||||
$pdo = db();
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT COALESCE(SUM(s.interest_amount), 0) AS total_interest
|
||||
FROM installment_schedules s
|
||||
JOIN installments i ON i.id = s.installment_id
|
||||
WHERE i.user_id = ?
|
||||
AND s.is_billed = 0
|
||||
");
|
||||
$stmt->execute([$userId]);
|
||||
$row = $stmt->fetch();
|
||||
|
||||
return (float)($row['total_interest'] ?? 0);
|
||||
}
|
||||
|
||||
function get_installment_remaining_total(int $userId): float
|
||||
{
|
||||
$pdo = db();
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT COALESCE(SUM(s.total_amount), 0) AS remaining_total
|
||||
FROM installment_schedules s
|
||||
JOIN installments i ON i.id = s.installment_id
|
||||
WHERE i.user_id = ?
|
||||
AND s.is_billed = 0
|
||||
");
|
||||
$stmt->execute([$userId]);
|
||||
$row = $stmt->fetch();
|
||||
|
||||
return (float)($row['remaining_total'] ?? 0);
|
||||
}
|
||||
|
||||
function recalculate_installment_status(int $installmentId): void
|
||||
{
|
||||
$pdo = db();
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT
|
||||
COALESCE(SUM(CASE WHEN is_billed = 0 THEN 1 ELSE 0 END), 0) AS remaining_count,
|
||||
COALESCE(MIN(CASE WHEN is_billed = 0 THEN cycle_no ELSE NULL END), 0) AS next_cycle
|
||||
FROM installment_schedules
|
||||
WHERE installment_id = ?
|
||||
");
|
||||
$stmt->execute([$installmentId]);
|
||||
$row = $stmt->fetch();
|
||||
|
||||
$remainingCount = (int)($row['remaining_count'] ?? 0);
|
||||
$nextCycle = (int)($row['next_cycle'] ?? 0);
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
UPDATE installments
|
||||
SET
|
||||
current_cycle = ?,
|
||||
is_completed = ?
|
||||
WHERE id = ?
|
||||
");
|
||||
$stmt->execute([
|
||||
$nextCycle > 0 ? $nextCycle : 0,
|
||||
$remainingCount === 0 ? 1 : 0,
|
||||
$installmentId
|
||||
]);
|
||||
}
|
||||
|
||||
function mark_installment_month_billed_for_card_payment(
|
||||
int $userId,
|
||||
int $cardAccountId,
|
||||
string $yearMonth
|
||||
): int {
|
||||
$pdo = db();
|
||||
$pdo->beginTransaction();
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT s.id, s.installment_id
|
||||
FROM installment_schedules s
|
||||
JOIN installments i ON i.id = s.installment_id
|
||||
WHERE i.user_id = ?
|
||||
AND i.account_id = ?
|
||||
AND s.bill_year_month = ?
|
||||
AND s.is_billed = 0
|
||||
ORDER BY s.id ASC
|
||||
");
|
||||
$stmt->execute([$userId, $cardAccountId, $yearMonth]);
|
||||
$rows = $stmt->fetchAll();
|
||||
|
||||
if (!$rows) {
|
||||
$pdo->commit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
$scheduleIds = array_column($rows, 'id');
|
||||
$installmentIds = array_values(array_unique(array_map(
|
||||
fn($r) => (int)$r['installment_id'],
|
||||
$rows
|
||||
)));
|
||||
|
||||
$placeholders = implode(',', array_fill(0, count($scheduleIds), '?'));
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
UPDATE installment_schedules
|
||||
SET is_billed = 1,
|
||||
billed_at = NOW()
|
||||
WHERE id IN ($placeholders)
|
||||
");
|
||||
$stmt->execute($scheduleIds);
|
||||
|
||||
foreach ($installmentIds as $installmentId) {
|
||||
recalculate_installment_status($installmentId);
|
||||
}
|
||||
|
||||
$pdo->commit();
|
||||
return count($scheduleIds);
|
||||
} catch (Throwable $e) {
|
||||
$pdo->rollBack();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
function prepay_installment(
|
||||
int $userId,
|
||||
int $installmentId,
|
||||
int $paymentAccountId,
|
||||
string $prepayDate,
|
||||
float $prepayPrincipalAmount,
|
||||
float $prepayInterestAmount = 0.0,
|
||||
?string $description = null,
|
||||
?int $targetScheduleId = null
|
||||
): void {
|
||||
$pdo = db();
|
||||
$pdo->beginTransaction();
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT i.*, t.merchant_name
|
||||
FROM installments i
|
||||
JOIN transactions t ON t.id = i.transaction_id
|
||||
WHERE i.id = ?
|
||||
AND i.user_id = ?
|
||||
");
|
||||
$stmt->execute([$installmentId, $userId]);
|
||||
$installment = $stmt->fetch();
|
||||
|
||||
if (!$installment) {
|
||||
throw new RuntimeException('할부 정보를 찾을 수 없습니다.');
|
||||
}
|
||||
|
||||
$prepayPrincipalAmount = (float)floor($prepayPrincipalAmount);
|
||||
$prepayInterestAmount = (float)floor($prepayInterestAmount);
|
||||
|
||||
if ($prepayPrincipalAmount <= 0 && $prepayInterestAmount <= 0) {
|
||||
throw new RuntimeException('선결제 금액이 0보다 커야 합니다.');
|
||||
}
|
||||
|
||||
$sql = "
|
||||
SELECT id, principal_amount, interest_amount, total_amount
|
||||
FROM installment_schedules
|
||||
WHERE installment_id = ?
|
||||
AND is_billed = 0
|
||||
";
|
||||
|
||||
$params = [$installmentId];
|
||||
|
||||
if ($targetScheduleId !== null && $targetScheduleId > 0) {
|
||||
$sql .= " AND id = ? ";
|
||||
$params[] = $targetScheduleId;
|
||||
}
|
||||
|
||||
$sql .= " ORDER BY cycle_no ASC ";
|
||||
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
$remainingSchedules = $stmt->fetchAll();
|
||||
|
||||
if (!$remainingSchedules) {
|
||||
throw new RuntimeException('남아있는 회차가 없습니다.');
|
||||
}
|
||||
|
||||
$remainingPrincipal = (float)floor(array_sum(array_map(
|
||||
fn($r) => (float)$r['principal_amount'],
|
||||
$remainingSchedules
|
||||
)));
|
||||
|
||||
$remainingInterest = (float)floor(array_sum(array_map(
|
||||
fn($r) => (float)$r['interest_amount'],
|
||||
$remainingSchedules
|
||||
)));
|
||||
|
||||
// 초과 입력 시 남은 금액까지만 자동 보정
|
||||
if ($prepayPrincipalAmount > $remainingPrincipal) {
|
||||
$prepayPrincipalAmount = $remainingPrincipal;
|
||||
}
|
||||
|
||||
if ($prepayInterestAmount > $remainingInterest) {
|
||||
$prepayInterestAmount = $remainingInterest;
|
||||
}
|
||||
|
||||
if ($prepayPrincipalAmount <= 0 && $prepayInterestAmount <= 0) {
|
||||
throw new RuntimeException('남아있는 선결제 가능 금액이 없습니다.');
|
||||
}
|
||||
|
||||
$remainingPrincipalToApply = $prepayPrincipalAmount;
|
||||
$remainingInterestToApply = $prepayInterestAmount;
|
||||
|
||||
foreach ($remainingSchedules as $schedule) {
|
||||
$scheduleId = (int)$schedule['id'];
|
||||
$principal = (float)$schedule['principal_amount'];
|
||||
$interest = (float)$schedule['interest_amount'];
|
||||
|
||||
$newPrincipal = $principal;
|
||||
$newInterest = $interest;
|
||||
|
||||
if ($remainingPrincipalToApply > 0) {
|
||||
$deduct = min($newPrincipal, $remainingPrincipalToApply);
|
||||
$newPrincipal = $newPrincipal - $deduct;
|
||||
$remainingPrincipalToApply = $remainingPrincipalToApply - $deduct;
|
||||
}
|
||||
|
||||
if ($remainingInterestToApply > 0) {
|
||||
$deduct = min($newInterest, $remainingInterestToApply);
|
||||
$newInterest = $newInterest - $deduct;
|
||||
$remainingInterestToApply = $remainingInterestToApply - $deduct;
|
||||
}
|
||||
|
||||
$newPrincipal = (float)max(0, floor($newPrincipal));
|
||||
$newInterest = (float)max(0, floor($newInterest));
|
||||
$newTotal = $newPrincipal + $newInterest;
|
||||
|
||||
$isNowZero = ($newTotal <= 0) ? 1 : 0;
|
||||
|
||||
$stmt2 = $pdo->prepare("
|
||||
UPDATE installment_schedules
|
||||
SET principal_amount = ?,
|
||||
interest_amount = ?,
|
||||
total_amount = ?,
|
||||
is_billed = CASE WHEN ? = 1 THEN 1 ELSE is_billed END,
|
||||
billed_at = CASE WHEN ? = 1 THEN NOW() ELSE billed_at END
|
||||
WHERE id = ?
|
||||
");
|
||||
|
||||
$stmt2->execute([
|
||||
$newPrincipal,
|
||||
$newInterest,
|
||||
$newTotal,
|
||||
$isNowZero,
|
||||
$isNowZero,
|
||||
$scheduleId
|
||||
]);
|
||||
}
|
||||
|
||||
$totalAmount = $prepayPrincipalAmount + $prepayInterestAmount;
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO installment_prepayments
|
||||
(
|
||||
user_id,
|
||||
installment_id,
|
||||
account_id,
|
||||
prepay_date,
|
||||
principal_amount,
|
||||
interest_amount,
|
||||
total_amount,
|
||||
description
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
");
|
||||
$stmt->execute([
|
||||
$userId,
|
||||
$installmentId,
|
||||
$paymentAccountId,
|
||||
$prepayDate,
|
||||
$prepayPrincipalAmount,
|
||||
$prepayInterestAmount,
|
||||
$totalAmount,
|
||||
$description
|
||||
]);
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
UPDATE installments
|
||||
SET
|
||||
prepaid_principal_amount = prepaid_principal_amount + ?,
|
||||
prepaid_interest_amount = prepaid_interest_amount + ?
|
||||
WHERE id = ?
|
||||
");
|
||||
$stmt->execute([
|
||||
$prepayPrincipalAmount,
|
||||
$prepayInterestAmount,
|
||||
$installmentId
|
||||
]);
|
||||
|
||||
recalculate_installment_status($installmentId);
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO transactions
|
||||
(
|
||||
user_id,
|
||||
account_id,
|
||||
category_id,
|
||||
transaction_type,
|
||||
amount,
|
||||
is_installment,
|
||||
installment_months,
|
||||
installment_interest_rate,
|
||||
installment_interest_total,
|
||||
installment_total_billed,
|
||||
installment_prepay_amount,
|
||||
transaction_date,
|
||||
merchant_name,
|
||||
description,
|
||||
related_account_id,
|
||||
fingerprint
|
||||
)
|
||||
VALUES (?, ?, ?, 'expense', ?, 0, NULL, 0, 0, NULL, ?, ?, ?, ?, NULL, ?)
|
||||
");
|
||||
|
||||
$desc = $description ?: '할부 선결제/중도상환';
|
||||
|
||||
$fingerprint = hash('sha256', implode('|', [
|
||||
$userId,
|
||||
$paymentAccountId,
|
||||
'installment_prepay',
|
||||
$installmentId,
|
||||
$prepayDate,
|
||||
number_format($totalAmount, 2, '.', ''),
|
||||
$desc
|
||||
]));
|
||||
|
||||
$stmtCat = $pdo->prepare("
|
||||
SELECT id
|
||||
FROM categories
|
||||
WHERE user_id = ?
|
||||
AND category_type = 'expense'
|
||||
AND name = '기타지출'
|
||||
LIMIT 1
|
||||
");
|
||||
$stmtCat->execute([$userId]);
|
||||
$category = $stmtCat->fetch();
|
||||
|
||||
if (!$category) {
|
||||
throw new RuntimeException('선결제 기록용 expense 카테고리(기타지출)를 찾을 수 없습니다.');
|
||||
}
|
||||
|
||||
$stmt->execute([
|
||||
$userId,
|
||||
$paymentAccountId,
|
||||
(int)$category['id'],
|
||||
$totalAmount,
|
||||
$totalAmount,
|
||||
$prepayDate,
|
||||
$installment['merchant_name'],
|
||||
'[할부 선결제] ' . $desc,
|
||||
$fingerprint
|
||||
]);
|
||||
|
||||
$pdo->commit();
|
||||
|
||||
recalculate_account_balance($paymentAccountId);
|
||||
} catch (Throwable $e) {
|
||||
$pdo->rollBack();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
function rebuild_all_installments_for_user(int $userId): int
|
||||
{
|
||||
$pdo = db();
|
||||
$pdo->beginTransaction();
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT
|
||||
id,
|
||||
account_id,
|
||||
amount,
|
||||
transaction_date,
|
||||
installment_months,
|
||||
installment_interest_rate,
|
||||
installment_interest_total,
|
||||
installment_total_billed
|
||||
FROM transactions
|
||||
WHERE user_id = ?
|
||||
AND transaction_type = 'expense'
|
||||
AND is_installment = 1
|
||||
AND installment_months > 1
|
||||
ORDER BY transaction_date ASC, id ASC
|
||||
");
|
||||
$stmt->execute([$userId]);
|
||||
$rows = $stmt->fetchAll();
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
DELETE ip
|
||||
FROM installment_prepayments ip
|
||||
JOIN installments i ON i.id = ip.installment_id
|
||||
WHERE i.user_id = ?
|
||||
");
|
||||
$stmt->execute([$userId]);
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
DELETE s
|
||||
FROM installment_schedules s
|
||||
JOIN installments i ON i.id = s.installment_id
|
||||
WHERE i.user_id = ?
|
||||
");
|
||||
$stmt->execute([$userId]);
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
DELETE FROM installments
|
||||
WHERE user_id = ?
|
||||
");
|
||||
$stmt->execute([$userId]);
|
||||
|
||||
$pdo->commit();
|
||||
|
||||
$count = 0;
|
||||
|
||||
foreach ($rows as $row) {
|
||||
create_installment_schedule(
|
||||
$userId,
|
||||
(int)$row['id'],
|
||||
(int)$row['account_id'],
|
||||
(float)$row['amount'],
|
||||
(int)$row['installment_months'],
|
||||
(string)$row['transaction_date'],
|
||||
(float)($row['installment_interest_rate'] ?? 0),
|
||||
$row['installment_interest_total'] !== null
|
||||
? (float)$row['installment_interest_total']
|
||||
: null,
|
||||
$row['installment_total_billed'] !== null
|
||||
? (float)$row['installment_total_billed']
|
||||
: null,
|
||||
((float)($row['installment_interest_rate'] ?? 0) > 0)
|
||||
? 'fixed_total'
|
||||
: 'none'
|
||||
);
|
||||
|
||||
$count++;
|
||||
}
|
||||
|
||||
return $count;
|
||||
} catch (Throwable $e) {
|
||||
if ($pdo->inTransaction()) {
|
||||
$pdo->rollBack();
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user