diff --git a/endpoints/subscription/add.php b/endpoints/subscription/add.php index 800d1843d..ba263a316 100644 --- a/endpoints/subscription/add.php +++ b/endpoints/subscription/add.php @@ -240,6 +240,10 @@ function resizeAndUploadLogo($uploadedFile, $uploadDir, $name, $settings) $inactive = isset($_POST['inactive']) ? true : false; $cancellationDate = $_POST['cancellation_date'] ?? null; $replacementSubscriptionId = $_POST['replacement_subscription_id']; +$paymentMethodLastFour = isset($_POST['payment_method_last_four']) ? preg_replace('/[^0-9]/', '', $_POST['payment_method_last_four']) : null; +if ($paymentMethodLastFour === '') { + $paymentMethodLastFour = null; +} if ($replacementSubscriptionId == 0 || $inactive == 0) { $replacementSubscriptionId = null; @@ -265,37 +269,38 @@ function resizeAndUploadLogo($uploadedFile, $uploadDir, $name, $settings) if (!$isEdit) { $sql = "INSERT INTO subscriptions ( - name, logo, price, currency_id, next_payment, cycle, frequency, notes, - payment_method_id, payer_user_id, category_id, notify, inactive, url, + name, logo, price, currency_id, next_payment, cycle, frequency, notes, + payment_method_id, payer_user_id, category_id, notify, inactive, url, notify_days_before, user_id, cancellation_date, replacement_subscription_id, - auto_renew, start_date + auto_renew, start_date, payment_method_last_four ) VALUES ( - :name, :logo, :price, :currencyId, :nextPayment, :cycle, :frequency, :notes, - :paymentMethodId, :payerUserId, :categoryId, :notify, :inactive, :url, + :name, :logo, :price, :currencyId, :nextPayment, :cycle, :frequency, :notes, + :paymentMethodId, :payerUserId, :categoryId, :notify, :inactive, :url, :notifyDaysBefore, :userId, :cancellationDate, :replacement_subscription_id, - :autoRenew, :startDate + :autoRenew, :startDate, :paymentMethodLastFour )"; } else { $id = $_POST['id']; - $sql = "UPDATE subscriptions SET - name = :name, - price = :price, + $sql = "UPDATE subscriptions SET + name = :name, + price = :price, currency_id = :currencyId, - next_payment = :nextPayment, + next_payment = :nextPayment, auto_renew = :autoRenew, start_date = :startDate, - cycle = :cycle, - frequency = :frequency, - notes = :notes, + cycle = :cycle, + frequency = :frequency, + notes = :notes, payment_method_id = :paymentMethodId, - payer_user_id = :payerUserId, - category_id = :categoryId, - notify = :notify, - inactive = :inactive, - url = :url, - notify_days_before = :notifyDaysBefore, - cancellation_date = :cancellationDate, - replacement_subscription_id = :replacement_subscription_id"; + payer_user_id = :payerUserId, + category_id = :categoryId, + notify = :notify, + inactive = :inactive, + url = :url, + notify_days_before = :notifyDaysBefore, + cancellation_date = :cancellationDate, + replacement_subscription_id = :replacement_subscription_id, + payment_method_last_four = :paymentMethodLastFour"; if ($logo != "") { $sql .= ", logo = :logo"; @@ -330,6 +335,7 @@ function resizeAndUploadLogo($uploadedFile, $uploadDir, $name, $settings) } $stmt->bindParam(':userId', $userId, SQLITE3_INTEGER); $stmt->bindParam(':replacement_subscription_id', $replacementSubscriptionId, SQLITE3_INTEGER); +$stmt->bindParam(':paymentMethodLastFour', $paymentMethodLastFour, SQLITE3_TEXT); if ($stmt->execute()) { $success['status'] = "Success"; diff --git a/endpoints/subscription/clone.php b/endpoints/subscription/clone.php index 5c2b2effc..0151f45ff 100644 --- a/endpoints/subscription/clone.php +++ b/endpoints/subscription/clone.php @@ -19,7 +19,7 @@ ])); } -$query = "INSERT INTO subscriptions (name, logo, price, currency_id, next_payment, cycle, frequency, notes, payment_method_id, payer_user_id, category_id, notify, url, inactive, notify_days_before, user_id, cancellation_date, replacement_subscription_id) VALUES (:name, :logo, :price, :currency_id, :next_payment, :cycle, :frequency, :notes, :payment_method_id, :payer_user_id, :category_id, :notify, :url, :inactive, :notify_days_before, :user_id, :cancellation_date, :replacement_subscription_id)"; +$query = "INSERT INTO subscriptions (name, logo, price, currency_id, next_payment, cycle, frequency, notes, payment_method_id, payer_user_id, category_id, notify, url, inactive, notify_days_before, user_id, cancellation_date, replacement_subscription_id, payment_method_last_four) VALUES (:name, :logo, :price, :currency_id, :next_payment, :cycle, :frequency, :notes, :payment_method_id, :payer_user_id, :category_id, :notify, :url, :inactive, :notify_days_before, :user_id, :cancellation_date, :replacement_subscription_id, :payment_method_last_four)"; $cloneStmt = $db->prepare($query); $cloneStmt->bindValue(':name', $subscriptionToClone['name'], SQLITE3_TEXT); $cloneStmt->bindValue(':logo', $subscriptionToClone['logo'], SQLITE3_TEXT); @@ -41,6 +41,7 @@ $cloneStmt->bindValue(':user_id', $userId, SQLITE3_INTEGER); $cloneStmt->bindValue(':cancellation_date', $subscriptionToClone['cancellation_date'], SQLITE3_TEXT); $cloneStmt->bindValue(':replacement_subscription_id', $subscriptionToClone['replacement_subscription_id'], SQLITE3_INTEGER); +$cloneStmt->bindValue(':payment_method_last_four', $subscriptionToClone['payment_method_last_four'], SQLITE3_TEXT); if ($cloneStmt->execute()) { $response = [ diff --git a/endpoints/subscription/get.php b/endpoints/subscription/get.php index 31bd2bf23..ed2680fbd 100644 --- a/endpoints/subscription/get.php +++ b/endpoints/subscription/get.php @@ -33,6 +33,7 @@ $subscriptionData['notify_days_before'] = $row['notify_days_before']; $subscriptionData['cancellation_date'] = $row['cancellation_date']; $subscriptionData['replacement_subscription_id'] = $row['replacement_subscription_id']; + $subscriptionData['payment_method_last_four'] = $row['payment_method_last_four']; $subscriptionJson = json_encode($subscriptionData); header('Content-Type: application/json'); diff --git a/endpoints/subscriptions/get.php b/endpoints/subscriptions/get.php index 0980d923f..0c6d4c145 100644 --- a/endpoints/subscriptions/get.php +++ b/endpoints/subscriptions/get.php @@ -172,6 +172,9 @@ $print[$id]['payment_method_icon'] = $paymentIconFolder . $payment_methods[$paymentMethodId]['icon']; $print[$id]['payment_method_name'] = $payment_methods[$paymentMethodId]['name']; $print[$id]['payment_method_id'] = $paymentMethodId; + if (isset($subscription['payment_method_last_four'])) { + $print[$id]['payment_method_last_four'] = $subscription['payment_method_last_four']; + } $print[$id]['category_id'] = $subscription['category_id']; $print[$id]['payer_user_id'] = $subscription['payer_user_id']; $print[$id]['price'] = floatval($subscription['price']); diff --git a/images/siteicons/svg/card.php b/images/siteicons/svg/card.php new file mode 100644 index 000000000..3b895106b --- /dev/null +++ b/images/siteicons/svg/card.php @@ -0,0 +1,7 @@ + + + + + + + diff --git a/includes/i18n/ca.php b/includes/i18n/ca.php index b53715aa7..6dfbcbbf3 100644 --- a/includes/i18n/ca.php +++ b/includes/i18n/ca.php @@ -108,6 +108,8 @@ "cycle" => "Cicle", "no_category" => "Sense categoria", "paid_by" => "Pagat per", + "last_four_digits" => "Últims 4 Dígits", + "last_four_digits_placeholder" => "1234", "url" => "URL", "notes" => "Notes", "enable_notifications" => "Activar notificacions per aquesta subscripció", diff --git a/includes/i18n/cs.php b/includes/i18n/cs.php index 78e4af3da..8de8084d9 100644 --- a/includes/i18n/cs.php +++ b/includes/i18n/cs.php @@ -108,6 +108,8 @@ "cycle" => "Cyklus", "no_category" => "Žádná kategorie", "paid_by" => "Platí", + "last_four_digits" => "Poslední 4 číslice", + "last_four_digits_placeholder" => "1234", "url" => "Adresa URL", "notes" => "Poznámky", "enable_notifications" => "Povolit oznámení pro toto předplatné", diff --git a/includes/i18n/da.php b/includes/i18n/da.php index 821ee85ae..2614f6b44 100644 --- a/includes/i18n/da.php +++ b/includes/i18n/da.php @@ -108,6 +108,8 @@ "cycle" => "Cyklus", "no_category" => "Ingen kategori", "paid_by" => "Betalt af", + "last_four_digits" => "Sidste 4 cifre", + "last_four_digits_placeholder" => "1234", "url" => "URL", "notes" => "Noter", "enable_notifications" => "Aktivér notifikationer for dette abonnement", diff --git a/includes/i18n/de.php b/includes/i18n/de.php index ea6cd6a8a..7da7802f7 100644 --- a/includes/i18n/de.php +++ b/includes/i18n/de.php @@ -108,6 +108,8 @@ "cycle" => "Zeitraum", "no_category" => "Keine Kategorie", "paid_by" => "Gezahlt durch", + "last_four_digits" => "Letzte 4 Ziffern", + "last_four_digits_placeholder" => "1234", "url" => "URL", "notes" => "Notizen", "enable_notifications" => "Benachrichtigungen für dieses Abonnement aktivieren", diff --git a/includes/i18n/el.php b/includes/i18n/el.php index b713e6740..7629502d9 100644 --- a/includes/i18n/el.php +++ b/includes/i18n/el.php @@ -108,6 +108,8 @@ "cycle" => "Κύκλος", "no_category" => "Καμία κατηγορία", "paid_by" => "Πληρώνεται από", + "last_four_digits" => "Τελευταία 4 Ψηφία", + "last_four_digits_placeholder" => "1234", "url" => "URL", "notes" => "Σημειώσεις", "enable_notifications" => "Ενεργοποίηση ειδοποιήσεων για αυτή τη συνδρομή", diff --git a/includes/i18n/en.php b/includes/i18n/en.php index c4ba8274e..e79f6d9b6 100644 --- a/includes/i18n/en.php +++ b/includes/i18n/en.php @@ -108,6 +108,8 @@ "cycle" => "Cycle", "no_category" => "No category", "paid_by" => "Paid by", + "last_four_digits" => "Last 4 Digits", + "last_four_digits_placeholder" => "1234", "url" => "URL", "notes" => "Notes", "enable_notifications" => "Enable Notifications for this subscription", diff --git a/includes/i18n/es.php b/includes/i18n/es.php index 6d630775b..854c3782f 100644 --- a/includes/i18n/es.php +++ b/includes/i18n/es.php @@ -108,6 +108,8 @@ "cycle" => "Ciclo", "no_category" => "Sin categoría", "paid_by" => "Pagado por", + "last_four_digits" => "Últimos 4 Dígitos", + "last_four_digits_placeholder" => "1234", "url" => "URL", "notes" => "Notas", "enable_notifications" => "Habilitar notificaciones para esta suscripción", diff --git a/includes/i18n/fr.php b/includes/i18n/fr.php index b743332d1..6dcf4474b 100644 --- a/includes/i18n/fr.php +++ b/includes/i18n/fr.php @@ -108,6 +108,8 @@ "cycle" => "Cycle", "no_category" => "Pas de catégorie", "paid_by" => "Payé par", + "last_four_digits" => "4 Derniers Chiffres", + "last_four_digits_placeholder" => "1234", "url" => "URL", "notes" => "Notes", "enable_notifications" => "Activer les notifications pour cet abonnement", diff --git a/includes/i18n/id.php b/includes/i18n/id.php index 7982ac71e..8a11adf35 100644 --- a/includes/i18n/id.php +++ b/includes/i18n/id.php @@ -108,6 +108,8 @@ "cycle" => "Siklus", "no_category" => "Tidak ada kategori", "paid_by" => "Dibayar oleh", + "last_four_digits" => "4 Digit Terakhir", + "last_four_digits_placeholder" => "1234", "url" => "URL", "notes" => "Catatan", "enable_notifications" => "Aktifkan Notifikasi untuk langganan ini", diff --git a/includes/i18n/it.php b/includes/i18n/it.php index 8308d76a1..bcb7e76ee 100644 --- a/includes/i18n/it.php +++ b/includes/i18n/it.php @@ -114,6 +114,8 @@ "cycle" => 'Ciclo', "no_category" => 'Nessuna categoria', "paid_by" => 'Pagato da', + "last_four_digits" => 'Ultime 4 cifre', + "last_four_digits_placeholder" => '1234', "url" => 'URL', "notes" => 'Note', "enable_notifications" => 'Abilita notifiche per questo abbonamento', diff --git a/includes/i18n/jp.php b/includes/i18n/jp.php index 383618998..9fd53f502 100644 --- a/includes/i18n/jp.php +++ b/includes/i18n/jp.php @@ -108,6 +108,8 @@ "cycle" => "サイクル", "no_category" => "カテゴリなし", "paid_by" => "支払い元", + "last_four_digits" => "下4桁", + "last_four_digits_placeholder" => "1234", "url" => "URL", "notes" => "注釈", "enable_notifications" => "この定期購入の通知を有効にする", diff --git a/includes/i18n/ko.php b/includes/i18n/ko.php index 58a9f835e..be08825dd 100644 --- a/includes/i18n/ko.php +++ b/includes/i18n/ko.php @@ -108,6 +108,8 @@ "cycle" => "주기", "no_category" => "카테고리 없음", "paid_by" => "결제하는 사람", + "last_four_digits" => "마지막 4자리", + "last_four_digits_placeholder" => "1234", "url" => "URL", "notes" => "메모", "enable_notifications" => "이 구독에 대한 알림을 활성화합니다.", diff --git a/includes/i18n/nl.php b/includes/i18n/nl.php index 5f43f0ca8..d533641cc 100644 --- a/includes/i18n/nl.php +++ b/includes/i18n/nl.php @@ -108,6 +108,8 @@ "cycle" => "Cyclus", "no_category" => "Geen categorie", "paid_by" => "Betaald door", + "last_four_digits" => "Laatste 4 cijfers", + "last_four_digits_placeholder" => "1234", "url" => "URL", "notes" => "Notities", "enable_notifications" => "Notificaties inschakelen voor dit abonnement", diff --git a/includes/i18n/pl.php b/includes/i18n/pl.php index 5f4bb1c50..a644626b3 100644 --- a/includes/i18n/pl.php +++ b/includes/i18n/pl.php @@ -108,6 +108,8 @@ "cycle" => "Cykl", "no_category" => "Brak kategorii", "paid_by" => "Zapłacone przez", + "last_four_digits" => "Ostatnie 4 cyfry", + "last_four_digits_placeholder" => "1234", "url" => "URL", "notes" => "Notatki", "enable_notifications" => "Włącz powiadomienia dla tej subskrypcji", diff --git a/includes/i18n/pt.php b/includes/i18n/pt.php index d7654bff3..e66a0eac4 100644 --- a/includes/i18n/pt.php +++ b/includes/i18n/pt.php @@ -108,6 +108,8 @@ "Cycle" => "Ciclo", "no_category" => "Sem categoria", "paid_by" => "Pago por", + "last_four_digits" => "Últimos 4 Dígitos", + "last_four_digits_placeholder" => "1234", "url" => "URL", "notes" => "Notas", "enable_notifications" => "Activar notificações para esta subscrição", diff --git a/includes/i18n/pt_br.php b/includes/i18n/pt_br.php index dfc6ae898..36cd46868 100644 --- a/includes/i18n/pt_br.php +++ b/includes/i18n/pt_br.php @@ -108,6 +108,8 @@ "cycle" => "Ciclo", "no_category" => "Sem categoria", "paid_by" => "Pago por", + "last_four_digits" => "Últimos 4 Dígitos", + "last_four_digits_placeholder" => "1234", "url" => "URL", "notes" => "Anotações", "enable_notifications" => "Ativar notificações para essa assinatura", diff --git a/includes/i18n/ru.php b/includes/i18n/ru.php index 613074118..c68f59e55 100644 --- a/includes/i18n/ru.php +++ b/includes/i18n/ru.php @@ -108,6 +108,8 @@ "cycle" => "Цикл", "no_category" => "Нет категории", "paid_by" => "Оплачивает", + "last_four_digits" => "Последние 4 цифры", + "last_four_digits_placeholder" => "1234", "url" => "URL", "notes" => "Примечания", "enable_notifications" => "Включить уведомления для этой подписки", diff --git a/includes/i18n/sl.php b/includes/i18n/sl.php index 2a5be0b16..a1a038d7c 100644 --- a/includes/i18n/sl.php +++ b/includes/i18n/sl.php @@ -108,6 +108,8 @@ "cycle" => "cikel", "no_category" => "Brez kategorije", "paid_by" => "Plačal", + "last_four_digits" => "Zadnje 4 številke", + "last_four_digits_placeholder" => "1234", "url" => "URL", "notes" => "Opombe", "enable_notifications" => "Omogoči obvestila za to naročnino", diff --git a/includes/i18n/sr.php b/includes/i18n/sr.php index 5c0dd9561..1c554a7d8 100644 --- a/includes/i18n/sr.php +++ b/includes/i18n/sr.php @@ -108,6 +108,8 @@ "cycle" => "Циклус", "no_category" => "Без категорије", "paid_by" => "Плаћено од", + "last_four_digits" => "Последње 4 цифре", + "last_four_digits_placeholder" => "1234", "url" => "URL", "notes" => "Напомене", "enable_notifications" => "Омогући обавештења за ову претплату", diff --git a/includes/i18n/sr_lat.php b/includes/i18n/sr_lat.php index 6640172d5..2d3e76443 100644 --- a/includes/i18n/sr_lat.php +++ b/includes/i18n/sr_lat.php @@ -108,6 +108,8 @@ "cycle" => "Ciklus", "no_category" => "Bez kategorije", "paid_by" => "Plaćeno od strane", + "last_four_digits" => "Poslednje 4 cifre", + "last_four_digits_placeholder" => "1234", "url" => "URL", "notes" => "Beleške", "enable_notifications" => "Omogući obaveštenja za ovu pretplatu", diff --git a/includes/i18n/tr.php b/includes/i18n/tr.php index f63de9bed..5424d9671 100644 --- a/includes/i18n/tr.php +++ b/includes/i18n/tr.php @@ -108,6 +108,8 @@ "cycle" => "Döngü", "no_category" => "Kategori yok", "paid_by" => "Ödeyen", + "last_four_digits" => "Son 4 Rakam", + "last_four_digits_placeholder" => "1234", "url" => "URL", "notes" => "Notlar", "enable_notifications" => "Bu abonelik için bildirimleri etkinleştir", diff --git a/includes/i18n/uk.php b/includes/i18n/uk.php index 077ac7efc..6fb7e47f5 100644 --- a/includes/i18n/uk.php +++ b/includes/i18n/uk.php @@ -108,6 +108,8 @@ "cycle" => "Цикл", "no_category" => "Немає категорії", "paid_by" => "Оплачує", + "last_four_digits" => "Останні 4 цифри", + "last_four_digits_placeholder" => "1234", "url" => "URL", "notes" => "Примітки", "enable_notifications" => "Увімкнути сповіщення для цієї підписки", diff --git a/includes/i18n/vi.php b/includes/i18n/vi.php index 9e4b323dc..147a1a089 100644 --- a/includes/i18n/vi.php +++ b/includes/i18n/vi.php @@ -108,6 +108,8 @@ "cycle" => "Chu kỳ", "no_category" => "Không có danh mục", "paid_by" => "Người thanh toán", + "last_four_digits" => "4 Số Cuối", + "last_four_digits_placeholder" => "1234", "url" => "URL", "notes" => "Ghi chú", "enable_notifications" => "Bật thông báo cho đăng ký này", diff --git a/includes/i18n/zh_cn.php b/includes/i18n/zh_cn.php index d6cb81fd9..e79218591 100644 --- a/includes/i18n/zh_cn.php +++ b/includes/i18n/zh_cn.php @@ -114,6 +114,8 @@ "cycle" => "周期", "no_category" => "无分类", "paid_by" => "付款人", + "last_four_digits" => "后四位数字", + "last_four_digits_placeholder" => "1234", "url" => "链接", "notes" => "备注", "enable_notifications" => "为此订阅启用通知", diff --git a/includes/i18n/zh_tw.php b/includes/i18n/zh_tw.php index b15e9e35e..d542e0f46 100644 --- a/includes/i18n/zh_tw.php +++ b/includes/i18n/zh_tw.php @@ -108,6 +108,8 @@ "cycle" => "週期", "no_category" => "未分類", "paid_by" => "付款人", + "last_four_digits" => "後四位數字", + "last_four_digits_placeholder" => "1234", "url" => "網址", "notes" => "備註", "enable_notifications" => "啟用此訂閱的通知", diff --git a/includes/list_subscriptions.php b/includes/list_subscriptions.php index 3f3c16f95..b69af59ac 100644 --- a/includes/list_subscriptions.php +++ b/includes/list_subscriptions.php @@ -319,6 +319,10 @@ class="name">"> + + **** + query("PRAGMA table_info(admin)"); -$columnExists = false; - -while ($row = $query->fetchArray(SQLITE3_ASSOC)) { - if ($row['name'] === 'local_webhook_notifications_allowlist') { - $columnExists = true; - break; - } -} - -if (!$columnExists) { - // Add the column with an empty string as the default - $db->exec("ALTER TABLE admin ADD COLUMN local_webhook_notifications_allowlist TEXT DEFAULT ''"); -} - -?> \ No newline at end of file +querySingle("SELECT COUNT(*) FROM pragma_table_info('subscriptions') WHERE name='payment_method_last_four'"); + +if (!$columnExists) { + $db->exec('ALTER TABLE subscriptions ADD COLUMN payment_method_last_four TEXT DEFAULT NULL'); +} + +?> +query("PRAGMA table_info(admin)"); +$columnExists = false; + +while ($row = $query->fetchArray(SQLITE3_ASSOC)) { + if ($row['name'] === 'local_webhook_notifications_allowlist') { + $columnExists = true; + break; + } +} + +if (!$columnExists) { + // Add the column with an empty string as the default + $db->exec("ALTER TABLE admin ADD COLUMN local_webhook_notifications_allowlist TEXT DEFAULT ''"); +} + +?> diff --git a/scripts/subscriptions.js b/scripts/subscriptions.js index fa011ee0a..677637f78 100644 --- a/scripts/subscriptions.js +++ b/scripts/subscriptions.js @@ -43,6 +43,8 @@ function resetForm() { replacementSubscriptionIdSelect.value = "0"; const replacementSubscription = document.querySelector(`#replacement_subscritpion`); replacementSubscription.classList.add("hide"); + const paymentMethodLastFour = document.querySelector("#payment_method_last_four"); + paymentMethodLastFour.value = ""; const form = document.querySelector("#subs-form"); form.reset(); closeLogoSearch(); @@ -77,6 +79,8 @@ function fillEditFormFields(subscription) { cycleSelect.value = subscription.cycle; const paymentSelect = document.querySelector("#payment_method"); paymentSelect.value = subscription.payment_method_id; + const paymentMethodLastFour = document.querySelector("#payment_method_last_four"); + paymentMethodLastFour.value = subscription.payment_method_last_four || ""; const categorySelect = document.querySelector("#category"); categorySelect.value = subscription.category_id; const payerSelect = document.querySelector("#payer_user"); diff --git a/subscriptions.php b/subscriptions.php index ff76f97d5..2ac2a83e7 100644 --- a/subscriptions.php +++ b/subscriptions.php @@ -252,6 +252,7 @@ $print[$id]['url'] = $subscription['url']; $print[$id]['notes'] = $subscription['notes']; $print[$id]['replacement_subscription_id'] = $subscription['replacement_subscription_id']; + $print[$id]['payment_method_last_four'] = $subscription['payment_method_last_four']; if (isset($settings['convertCurrency']) && $settings['convertCurrency'] === 'true' && $currencyId != $mainCurrencyId) { $print[$id]['price'] = getPriceConverted($print[$id]['price'], $currencyId, $db); @@ -427,6 +428,15 @@ class="button secondary-button autofill-next-payment hideOnMobile" ?> +
+ + +
+ + + +
+
+
+ + +
-
- - -
-