This commit is contained in:
2026-03-30 20:23:38 +02:00
parent 70662afd2c
commit 5435209b08
26 changed files with 1949 additions and 160 deletions

View File

@@ -16,6 +16,8 @@ use App\Modules\Email\EmailSendingService;
use App\Modules\Settings\EmailMailboxRepository;
use App\Modules\Settings\EmailTemplateRepository;
use App\Modules\Settings\ReceiptConfigRepository;
use App\Modules\Settings\ShopproApiClient;
use App\Modules\Settings\ShopproIntegrationsRepository;
use App\Modules\Shipments\ShipmentPackageRepository;
final class OrdersController
@@ -32,7 +34,8 @@ final class OrdersController
private readonly ?EmailTemplateRepository $emailTemplateRepo = null,
private readonly ?EmailMailboxRepository $emailMailboxRepo = null,
private readonly string $storagePath = '',
private readonly ?\App\Modules\Printing\PrintJobRepository $printJobRepo = null
private readonly ?\App\Modules\Printing\PrintJobRepository $printJobRepo = null,
private readonly ?ShopproIntegrationsRepository $shopproIntegrations = null
) {
}
@@ -781,4 +784,102 @@ final class OrdersController
return Response::json($preview);
}
public function addPayment(Request $request): Response
{
$orderId = max(0, (int) $request->input('id', 0));
if ($orderId <= 0) {
return Response::json(['ok' => false, 'error' => 'Nieprawidłowe ID zamówienia.'], 400);
}
if (!Csrf::verify((string) $request->input('_token', ''))) {
return Response::json(['ok' => false, 'error' => 'Nieprawidłowy token CSRF.'], 403);
}
$amount = (float) $request->input('amount', 0);
$paymentTypeId = trim((string) $request->input('payment_type_id', ''));
$paymentDate = trim((string) $request->input('payment_date', ''));
$comment = trim((string) $request->input('comment', ''));
if ($amount <= 0) {
return Response::json(['ok' => false, 'error' => 'Kwota musi być większa od 0.'], 422);
}
if ($paymentTypeId === '') {
return Response::json(['ok' => false, 'error' => 'Wybierz typ płatności.'], 422);
}
$result = $this->orders->addPayment($orderId, [
'amount' => $amount,
'payment_type_id' => $paymentTypeId,
'payment_date' => $paymentDate !== '' ? $paymentDate . ' ' . date('H:i:s') : '',
'comment' => $comment,
]);
if ($result === null) {
return Response::json(['ok' => false, 'error' => 'Nie udało się zapisać płatności.'], 500);
}
$this->orders->recordActivity(
$orderId,
'payment',
'Dodano płatność: ' . number_format($amount, 2, '.', ' ') . ' PLN (' . $paymentTypeId . ')',
['payment_id' => $result['id'], 'amount' => $amount, 'type' => $paymentTypeId],
'user',
$this->auth->user()['name'] ?? null
);
$this->pushPaymentToShoppro($orderId, $result['payment_status']);
return Response::json([
'ok' => true,
'payment_id' => $result['id'],
'payment_status' => $result['payment_status'],
'total_paid' => $result['total_paid'],
]);
}
private function pushPaymentToShoppro(int $orderId, int $paymentStatus): void
{
if ($paymentStatus !== 2 || $this->shopproIntegrations === null) {
return;
}
try {
$orderStmt = $this->orders->findOrderSourceInfo($orderId);
if ($orderStmt === null || ($orderStmt['source'] ?? '') !== 'shoppro') {
return;
}
$integrationId = (int) ($orderStmt['integration_id'] ?? 0);
$sourceOrderId = trim((string) ($orderStmt['source_order_id'] ?? ''));
if ($integrationId <= 0 || $sourceOrderId === '') {
return;
}
$integration = $this->shopproIntegrations->findIntegration($integrationId);
if ($integration === null || empty($integration['is_active']) || empty($integration['has_api_key'])) {
return;
}
$baseUrl = trim((string) ($integration['base_url'] ?? ''));
$apiKey = $this->shopproIntegrations->getApiKeyDecrypted($integrationId);
if ($baseUrl === '' || $apiKey === null || trim($apiKey) === '') {
return;
}
$client = new ShopproApiClient();
$pushResult = $client->setOrderPaid($baseUrl, $apiKey, 10, $sourceOrderId);
$this->orders->recordActivity(
$orderId,
'sync',
$pushResult['ok']
? 'Wysłano status płatności do shopPRO (opłacone)'
: 'Błąd push płatności do shopPRO: ' . ($pushResult['message'] ?? 'unknown'),
['direction' => 'push', 'target' => 'shoppro', 'ok' => $pushResult['ok']],
'system'
);
} catch (\Throwable) {
}
}
}

View File

@@ -847,6 +847,94 @@ final class OrdersRepository
], $actorType, $actorName);
}
/**
* @param array<string, mixed> $data Keys: payment_type_id, amount, payment_date, comment, currency
* @return array{id:int, payment_status:int, total_paid:float}|null
*/
/**
* @return array{source:string, integration_id:int, source_order_id:string}|null
*/
public function findOrderSourceInfo(int $orderId): ?array
{
if ($orderId <= 0) {
return null;
}
$stmt = $this->pdo->prepare('SELECT source, integration_id, source_order_id FROM orders WHERE id = :id LIMIT 1');
$stmt->execute(['id' => $orderId]);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
return is_array($row) ? $row : null;
}
/**
* @param array<string, mixed> $data Keys: payment_type_id, amount, payment_date, comment, currency
* @return array{id:int, payment_status:int, total_paid:float}|null
*/
public function addPayment(int $orderId, array $data): ?array
{
if ($orderId <= 0) {
return null;
}
$stmt = $this->pdo->prepare('SELECT id, total_with_tax, currency FROM orders WHERE id = :id LIMIT 1');
$stmt->execute(['id' => $orderId]);
$order = $stmt->fetch(PDO::FETCH_ASSOC);
if (!is_array($order)) {
return null;
}
$amount = round((float) ($data['amount'] ?? 0), 2);
$paymentTypeId = trim((string) ($data['payment_type_id'] ?? ''));
$paymentDate = trim((string) ($data['payment_date'] ?? ''));
$comment = trim((string) ($data['comment'] ?? ''));
$currency = trim((string) ($data['currency'] ?? $order['currency'] ?? 'PLN'));
if ($amount <= 0 || $paymentTypeId === '') {
return null;
}
$sourcePaymentId = 'manual_' . $orderId . '_' . time();
$insert = $this->pdo->prepare(
'INSERT INTO order_payments (order_id, source_payment_id, payment_type_id, payment_date, amount, currency, comment, created_at, updated_at)
VALUES (:order_id, :source_payment_id, :payment_type_id, :payment_date, :amount, :currency, :comment, NOW(), NOW())'
);
$insert->execute([
'order_id' => $orderId,
'source_payment_id' => $sourcePaymentId,
'payment_type_id' => $paymentTypeId,
'payment_date' => $paymentDate !== '' ? $paymentDate : date('Y-m-d H:i:s'),
'amount' => $amount,
'currency' => $currency,
'comment' => $comment !== '' ? $comment : null,
]);
$paymentId = (int) $this->pdo->lastInsertId();
$sumStmt = $this->pdo->prepare('SELECT COALESCE(SUM(amount), 0) FROM order_payments WHERE order_id = :order_id');
$sumStmt->execute(['order_id' => $orderId]);
$totalPaid = round((float) $sumStmt->fetchColumn(), 2);
$totalWithTax = $order['total_with_tax'] !== null ? (float) $order['total_with_tax'] : null;
$paymentStatus = 0;
if ($totalPaid > 0 && $totalWithTax !== null && $totalPaid >= $totalWithTax) {
$paymentStatus = 2;
} elseif ($totalPaid > 0) {
$paymentStatus = 1;
}
$update = $this->pdo->prepare('UPDATE orders SET payment_status = :payment_status, total_paid = :total_paid, updated_at = NOW() WHERE id = :id');
$update->execute([
'payment_status' => $paymentStatus,
'total_paid' => $totalPaid,
'id' => $orderId,
]);
return [
'id' => $paymentId,
'payment_status' => $paymentStatus,
'total_paid' => $totalPaid,
];
}
public function updateOrderStatus(int $orderId, string $newStatusCode, string $actorType = 'user', ?string $actorName = null): bool
{
try {