diff --git a/components/control/PaymentsPendingPanel.tsx b/components/control/PaymentsPendingPanel.tsx index 6c944ff..fb6c355 100644 --- a/components/control/PaymentsPendingPanel.tsx +++ b/components/control/PaymentsPendingPanel.tsx @@ -3,11 +3,18 @@ import { getTranslations } from "next-intl/server"; /** * "Card payments are on their way" (SOFRA-PAYMENTS-PLAN §9 P4). * - * The one window nothing else covers. A self-serve buyer of `online-payments` is - * provisioned WITHOUT it — P1 makes the module and the connected account a pair, - * because `provision-tenant.sh` refuses one without the other and refuses it before - * the database — so they go live on everything else and trade on cash while their - * Stripe account is being verified. Every other surface is honest about that state + * The one window nothing else covers. A buyer of `online-payments` is provisioned + * WITHOUT it — P1 makes the module and the connected account a pair, because + * `provision-tenant.sh` refuses one without the other and refuses it before the + * database — so they go live on everything else and trade on cash meanwhile. + * + * WHAT THIS WINDOW NOW MEANS (ADR-011 amendment). It used to be the ordinary state + * of every self-serve buyer, on the premise that only the restaurant could create a + * Stripe account. The control plane MINTS the account now, so reaching this panel + * means OUR creation did not happen — which makes "there is nothing for you to do + * right now" more true than it was, not less: the outstanding work is ours. That is + * also why the copy still gives no estimate and still names nothing they cannot act + * on; the failure is on our side of a wall they cannot see. Every other surface is honest about that state * and silent about it: RUMI's own checklist cannot see the purchase (only the grant), * and the tenant's checkout simply does not offer a card. Only this dashboard holds * both halves, so only this dashboard can say the thing out loud. @@ -38,14 +45,14 @@ export default async function PaymentsPendingPanel({ locale }: { readonly locale
{t("title")}
{t("body")}
{t("billingNote")}
- - {t("stripeLink")} - + {/* Prose, not a link, and that is the Express change (ADR-011 amendment). + This used to be an to https://dashboard.stripe.com. Under Express a + restaurant has no full Stripe dashboard to log into, and in THIS state + they have no account at all — so that link led somewhere they could not + get in. The sentence it carried was still useful ("your own Stripe view is + coming, here is what it will ask"), so it is re-stated rather than + deleted: what the short form asks for, and why no link can be kept. */} +{t("nextStep")}
); } diff --git a/messages/ar.json b/messages/ar.json index 0095d4f..fb82a82 100644 --- a/messages/ar.json +++ b/messages/ar.json @@ -1012,7 +1012,7 @@ "rateLabel": "المعدل (نقاط أساس، 100 = 1٪)", "rateHint": "مثال: 150 = 1.50٪. الحد الأقصى {max} نقطة أساس.", "notEligibleRegistryUnavailable": "تعذّرت قراءة سجل المستأجرين، لذا لا يمكن التحقق من أهلية العمولة الآن.", - "notEligibleNotPaired": "سجل هذا المستأجر لا يتضمّن online-payments وstripe_account معًا — يرفض التجهيز أي معدل أكبر من صفر بدون هذا الاقتران، قبل قاعدة البيانات. تبقى العمولة معطّلة حتى يتوفّر الاثنان.", + "notEligibleNotPaired": "لا يحمل سجل هذا المطعم كلاً من online-payments و stripe_account معًا — ويرفض التزويد أي نسبة أكبر من صفر بدون هذا الاقتران، وقبل قاعدة البيانات. صرنا نفتح حساب Stripe بأنفسنا، فغيابه يعني أن الاقتراح لم يستطع إنشاءه (والسبب مذكور في طلب الدمج) أو أن السجل أقدم من ذلك. تبقى العمولة معطّلة حتى يتوفّر الاثنان.", "submit": "حفظ", "saving": "جارٍ الحفظ…", "prOpened": "تم فتح طلب سحب للسجل — ادمجه، ثم أعد تجهيز المستأجر.", @@ -1222,18 +1222,18 @@ "rateLabel": "المعدل (نقاط أساس، 100 = 1٪)", "rateHint": "مثال: 150 = 1.50٪. الحد الأقصى {max} نقطة أساس.", "notEligibleRegistryUnavailable": "لا يمكننا التحقق من إعداد هذا العميل الآن، لذا تبقى العمولة معطّلة في الوقت الحالي.", - "notEligibleNotPaired": "تتطلب العمولة أن يمتلك هذا العميل وحدة المدفوعات عبر الإنترنت وحساب Stripe خاصًا به. اطلب منّا الاثنين، وسيُفتح هذا الخيار.", + "notEligibleNotPaired": "تتطلّب العمولة أن يكون لدى هذا العميل وحدة online-payments وحساب Stripe. نحن من يفتح هذا الحساب له، فإن كان غائبًا فقد أخفق شيء لدينا — أخبرنا، وسيُفتح هذا الخيار.", "submit": "حفظ", "saving": "جارٍ الحفظ…", "prOpened": "أُرسل إلى SofraPiwas. سنطبّقه على تطبيق عميلك ونؤكد لك — لم يتغيّر شيء في صفحة الدفع بعد.", "alreadySet": "تطبيق عميلك يعمل بهذا المعدل بالفعل. لا شيء لإرساله." }, "paymentsPending": { - "kicker": "الدفع بالبطاقة", - "title": "الدفع بالبطاقة في طريقه إليك", - "body": "الدفع بالبطاقة جزء من باقتك. نحن نقوم بتفعيله لك الآن — لا شيء عليك فعله في هذه اللحظة، وسنخبرك فور ظهوره عند صندوقك. حتى ذلك الحين مطعمك يعمل بالكامل ويقبل النقد كالمعتاد.", - "billingNote": "تُحتسب فاتورة باقتك من يوم بدايتها. إذا لم يكن الدفع بالبطاقة مفعّلًا بعد عند وصول فاتورتك الأولى، أخبرنا وسنُقيّد لك ذلك الشهر.", - "stripeLink": "لوحة Stripe الخاصة بك" + "kicker": "المدفوعات بالبطاقة", + "title": "مدفوعاتك بالبطاقة في الطريق", + "body": "المدفوعات بالبطاقة ضمن باقتك. نحن من يفتح حساب Stripe نيابةً عنك، فلا شيء عليك فعله الآن — وسنخبرك فور ظهور البطاقة في نقطة البيع لديك. حتى ذلك الحين مطعمك يعمل بالكامل ويقبل النقد كالمعتاد.", + "billingNote": "تُحتسب باقتك من يوم بدايتها. وإذا لم تكن المدفوعات بالبطاقة مفعّلة عند وصول فاتورتك الأولى، أخبرنا وسنقيّد لك ذلك الشهر.", + "nextStep": "عندما يحين دورك سيعرض عليك Stripe نموذجًا قصيرًا: تاريخ ميلادك، ورقم هاتف، والموافقة على شروطهم. سنرسل لك ذلك الرابط في حينه؛ ورابط Stripe لا يبقى صالحًا سوى دقائق معدودة، فلا فائدة من الاحتفاظ به." }, "invoice": { "title": "فاتورة", diff --git a/messages/de.json b/messages/de.json index 71eba5e..5e1646b 100644 --- a/messages/de.json +++ b/messages/de.json @@ -1012,7 +1012,7 @@ "rateLabel": "Satz (Basispunkte, 100 = 1 %)", "rateHint": "z. B. 150 = 1,50 %. Obergrenze {max} Basispunkte.", "notEligibleRegistryUnavailable": "Das Tenant-Registry konnte nicht gelesen werden, daher kann die Provisionsberechtigung gerade nicht geprüft werden.", - "notEligibleNotPaired": "Der Registry-Eintrag dieses Tenants enthält nicht beide, online-payments UND ein stripe_account — die Provisionierung lehnt einen Satz über null ohne dieses Paar ab, noch vor der Datenbank. Provision bleibt aus, bis beides vorhanden ist.", + "notEligibleNotPaired": "Der Registry-Eintrag dieses Betriebs führt nicht beides — online-payments und ein stripe_account. Das Provisioning verweigert einen Satz über null ohne dieses Paar, und zwar vor der Datenbank. Das Stripe-Konto eröffnen inzwischen wir, ein fehlendes heißt also: der Vorschlag konnte es nicht anlegen (sein PR nennt den Grund) oder der Eintrag ist älter. Die Provision bleibt aus, bis beides da ist.", "submit": "Speichern", "saving": "Wird gespeichert…", "prOpened": "Registry-PR geöffnet — zusammenführen, dann den Tenant erneut bereitstellen.", @@ -1222,18 +1222,18 @@ "rateLabel": "Satz (Basispunkte, 100 = 1 %)", "rateHint": "z. B. 150 = 1,50 %. Obergrenze {max} Basispunkte.", "notEligibleRegistryUnavailable": "Wir können die Einrichtung dieses Kunden gerade nicht prüfen, deshalb bleibt die Provision vorerst aus.", - "notEligibleNotPaired": "Für die Provision braucht dieser Kunde das Online-Zahlungsmodul und ein eigenes Stripe-Konto. Fragen Sie uns nach beidem, dann steht diese Wahl offen.", + "notEligibleNotPaired": "Für die Provision braucht dieser Kunde das Modul online-payments und ein Stripe-Konto. Dieses Konto eröffnen wir für ihn — fehlt es, ist bei uns etwas schiefgegangen. Sagen Sie uns Bescheid, dann lässt sich dieser Schalter umlegen.", "submit": "Speichern", "saving": "Wird gespeichert…", "prOpened": "An SofraPiwas gesendet. Wir wenden es auf die App Ihres Kunden an und bestätigen — an der Kasse hat sich noch nichts geändert.", "alreadySet": "Die App Ihres Kunden läuft bereits mit diesem Satz. Nichts zu senden." }, "paymentsPending": { - "kicker": "Kartenzahlung", - "title": "Ihre Kartenzahlung ist unterwegs", - "body": "Kartenzahlung gehört zu Ihrem Paket. Wir schalten sie gerade für Sie frei — Sie müssen im Moment nichts tun, und wir sagen Ihnen Bescheid, sobald sie an Ihrer Kasse auftaucht. Bis dahin ist Ihr Restaurant vollständig online und nimmt wie gewohnt Bargeld an.", - "billingNote": "Ihr Paket wird ab dem Starttag abgerechnet. Ist die Kartenzahlung bei Ihrer ersten Rechnung noch nicht freigeschaltet, sagen Sie uns Bescheid — wir schreiben Ihnen diesen Monat gut.", - "stripeLink": "Ihr Stripe-Dashboard" + "kicker": "Kartenzahlungen", + "title": "Ihre Kartenzahlungen sind unterwegs", + "body": "Kartenzahlungen gehören zu Ihrem Tarif. Das Stripe-Konto eröffnen wir für Sie — Sie müssen also gerade nichts tun, und wir sagen Ihnen Bescheid, sobald die Karte an Ihrer Kasse erscheint. Bis dahin ist Ihr Restaurant vollständig live und nimmt wie gewohnt Bargeld an.", + "billingNote": "Ihr Tarif wird ab dem Starttag berechnet. Sind die Kartenzahlungen bei Ihrer ersten Rechnung immer noch nicht aktiv, sagen Sie uns Bescheid — wir schreiben Ihnen diesen Monat gut.", + "nextStep": "Wenn es so weit ist, zeigt Ihnen Stripe ein kurzes Formular: Geburtsdatum, eine Telefonnummer und die Zustimmung zu deren Bedingungen. Den Link dazu schicken wir Ihnen, wenn Sie an der Reihe sind; ein Stripe-Link gilt nur wenige Minuten, aufheben lohnt sich also nie." }, "invoice": { "title": "Rechnung", diff --git a/messages/en.json b/messages/en.json index 6eee570..9b98510 100644 --- a/messages/en.json +++ b/messages/en.json @@ -1012,7 +1012,7 @@ "rateLabel": "Rate (basis points, 100 = 1%)", "rateHint": "e.g. 150 = 1.50%. Ceiling {max} bps.", "notEligibleRegistryUnavailable": "The tenant registry could not be read, so commission eligibility cannot be checked right now.", - "notEligibleNotPaired": "This tenant's registry entry does not carry both online-payments and a stripe_account — provisioning refuses a non-zero rate without that pair, before the database. Commission stays off until both are there.", + "notEligibleNotPaired": "This tenant's registry entry does not carry both online-payments and a stripe_account — provisioning refuses a non-zero rate without that pair, before the database. We open the Stripe account ourselves now, so a missing one means the proposal could not create it (its PR says why) or the entry predates that. Commission stays off until both are there.", "submit": "Save", "saving": "Saving…", "prOpened": "Registry PR opened — merge it, then re-provision the tenant.", @@ -1222,7 +1222,7 @@ "rateLabel": "Rate (basis points, 100 = 1%)", "rateHint": "e.g. 150 = 1.50%. Ceiling {max} bps.", "notEligibleRegistryUnavailable": "We can't check this client's setup right now, so commission stays off for the moment.", - "notEligibleNotPaired": "Commission needs this client to have the online-payments module and their own Stripe account. Ask us for both, and this switch opens up.", + "notEligibleNotPaired": "Commission needs this client's tenant to have the online-payments module and a Stripe account. We open that account for them, so if it is missing something went wrong on our side — ask us, and this switch opens up.", "submit": "Save", "saving": "Saving…", "prOpened": "Sent to SofraPiwas. We apply it to your client's app and confirm — nothing has changed at their checkout yet.", @@ -1231,9 +1231,9 @@ "paymentsPending": { "kicker": "Card payments", "title": "Card payments are on their way", - "body": "You bought card payments with your plan. We're switching them on for you — there's nothing for you to do right now, and we'll tell you the moment they appear at your checkout. Until then your restaurant is fully live and taking cash as usual.", + "body": "You bought card payments with your plan. We open the Stripe account for you, so there is nothing for you to do right now — and we will tell you the moment cards appear at your checkout. Until then your restaurant is fully live and taking cash as usual.", "billingNote": "Your plan is billed from the day it started. If card payments still aren't switched on when your first invoice arrives, just ask us and we'll credit that month.", - "stripeLink": "Your Stripe dashboard" + "nextStep": "When it is ready you will get one short form from Stripe — your date of birth, a phone number, and agreeing to their terms. We will send you that link when it is your turn; a Stripe link only stays alive for a few minutes, so it is never worth keeping one." }, "invoice": { "title": "Invoice", diff --git a/messages/fr.json b/messages/fr.json index b749abe..21075c9 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -1012,7 +1012,7 @@ "rateLabel": "Taux (points de base, 100 = 1 %)", "rateHint": "ex. 150 = 1,50 %. Plafond {max} points de base.", "notEligibleRegistryUnavailable": "Le registre des tenants n'a pas pu être lu, l'éligibilité à la commission ne peut donc pas être vérifiée pour l'instant.", - "notEligibleNotPaired": "L'entrée de registre de ce tenant ne comporte pas à la fois online-payments et un stripe_account — le provisionnement refuse un taux non nul sans ce couple, avant même la base de données. La commission reste désactivée tant que les deux ne sont pas présents.", + "notEligibleNotPaired": "L'entrée de ce restaurant ne porte pas à la fois online-payments et un stripe_account — le provisioning refuse un taux non nul sans cette paire, avant la base de données. C'est nous qui ouvrons désormais le compte Stripe : son absence signifie donc que la proposition n'a pas pu le créer (sa PR en donne la raison), ou que l'entrée est antérieure. La commission reste désactivée tant que les deux ne sont pas là.", "submit": "Enregistrer", "saving": "Enregistrement…", "prOpened": "PR de registre ouverte — fusionnez-la, puis reprovisionnez le tenant.", @@ -1222,7 +1222,7 @@ "rateLabel": "Taux (points de base, 100 = 1 %)", "rateHint": "ex. 150 = 1,50 %. Plafond {max} points de base.", "notEligibleRegistryUnavailable": "Nous ne pouvons pas vérifier la configuration de ce client pour l'instant : la commission reste donc désactivée.", - "notEligibleNotPaired": "La commission exige que ce client dispose du module de paiements en ligne et de son propre compte Stripe. Demandez-nous les deux et ce choix s'ouvrira.", + "notEligibleNotPaired": "La commission exige que ce client dispose du module online-payments et d'un compte Stripe. Ce compte, c'est nous qui l'ouvrons pour lui : s'il manque, c'est que quelque chose a échoué de notre côté — demandez-nous, et ce réglage s'ouvrira.", "submit": "Enregistrer", "saving": "Enregistrement…", "prOpened": "Envoyé à SofraPiwas. Nous l'appliquons à l'application de votre client et vous confirmons — rien n'a encore changé à son encaissement.", @@ -1231,9 +1231,9 @@ "paymentsPending": { "kicker": "Paiements par carte", "title": "Vos paiements par carte arrivent", - "body": "Votre offre inclut les paiements par carte. Nous sommes en train de les activer pour vous — vous n'avez rien à faire pour l'instant, et nous vous préviendrons dès qu'ils apparaîtront à votre caisse. D'ici là, votre restaurant est pleinement en ligne et encaisse les espèces comme d'habitude.", - "billingNote": "Votre offre est facturée à partir du jour où elle a démarré. Si les paiements par carte ne sont toujours pas activés à l'arrivée de votre première facture, demandez-nous et nous créditons ce mois-là.", - "stripeLink": "Votre tableau de bord Stripe" + "body": "Vous avez pris les paiements par carte avec votre formule. C'est nous qui ouvrons le compte Stripe pour vous : vous n'avez donc rien à faire pour l'instant, et nous vous prévenons dès que la carte apparaît à votre caisse. D'ici là, votre restaurant est pleinement en ligne et encaisse en espèces comme d'habitude.", + "billingNote": "Votre formule est facturée à partir du jour de son démarrage. Si les paiements par carte ne sont toujours pas actifs à l'arrivée de votre première facture, demandez-nous et nous créditons ce mois-là.", + "nextStep": "Le moment venu, Stripe vous présentera un court formulaire : votre date de naissance, un numéro de téléphone, et l'acceptation de leurs conditions. Nous vous transmettrons ce lien quand ce sera votre tour ; un lien Stripe ne reste valable que quelques minutes, il ne sert donc jamais à rien d'en garder un." }, "invoice": { "title": "Facture", diff --git a/messages/nl.json b/messages/nl.json index 5ab76e9..8aacb17 100644 --- a/messages/nl.json +++ b/messages/nl.json @@ -1012,7 +1012,7 @@ "rateLabel": "Tarief (basispunten, 100 = 1%)", "rateHint": "bijv. 150 = 1,50%. Maximum {max} basispunten.", "notEligibleRegistryUnavailable": "Het tenant-register kon niet worden gelezen, dus de commissie-geschiktheid kan nu niet worden gecontroleerd.", - "notEligibleNotPaired": "De registry-entry van dit tenant bevat niet zowel online-payments als een stripe_account — provisionering weigert een tarief boven nul zonder dat paar, vóór de database. Commissie blijft uit totdat beide aanwezig zijn.", + "notEligibleNotPaired": "De registry-regel van deze zaak bevat niet zowel online-payments als een stripe_account — provisioning weigert een tarief boven nul zonder dat paar, en wel vóór de database. Wij openen het Stripe-account nu zelf, dus als het ontbreekt kon het voorstel het niet aanmaken (de PR zegt waarom) of dateert de regel van eerder. Commissie blijft uit tot beide er zijn.", "submit": "Opslaan", "saving": "Opslaan…", "prOpened": "Registry-PR geopend — voeg samen en richt het tenant opnieuw in.", @@ -1222,7 +1222,7 @@ "rateLabel": "Tarief (basispunten, 100 = 1%)", "rateHint": "bijv. 150 = 1,50%. Maximum {max} basispunten.", "notEligibleRegistryUnavailable": "We kunnen de inrichting van deze klant nu niet controleren, dus commissie blijft voorlopig uit.", - "notEligibleNotPaired": "Voor commissie heeft deze klant de module online betalingen en een eigen Stripe-account nodig. Vraag ons om beide, dan gaat deze keuze open.", + "notEligibleNotPaired": "Commissie vereist dat deze klant de module online-payments en een Stripe-account heeft. Dat account openen wij voor hen, dus als het ontbreekt is er bij ons iets misgegaan — vraag het ons, dan gaat deze schakelaar open.", "submit": "Opslaan", "saving": "Opslaan…", "prOpened": "Verstuurd naar SofraPiwas. Wij passen het toe op de app van uw klant en bevestigen — bij hun kassa is nog niets veranderd.", @@ -1230,10 +1230,10 @@ }, "paymentsPending": { "kicker": "Kaartbetalingen", - "title": "Uw kaartbetalingen zijn onderweg", - "body": "Kaartbetalingen horen bij uw pakket. We zetten ze nu voor u aan — u hoeft op dit moment niets te doen, en we laten het weten zodra ze bij uw kassa verschijnen. Tot die tijd staat uw restaurant volledig online en neemt het gewoon contant geld aan.", - "billingNote": "Uw pakket wordt gefactureerd vanaf de dag dat het startte. Staan de kaartbetalingen bij uw eerste factuur nog niet aan? Laat het ons weten, dan crediteren we die maand.", - "stripeLink": "Uw Stripe-dashboard" + "title": "Je kaartbetalingen zijn onderweg", + "body": "Kaartbetalingen horen bij je pakket. Wij openen de Stripe-rekening voor je, dus je hoeft nu niets te doen — en we laten het weten zodra de kaart bij je kassa verschijnt. Tot dan is je restaurant volledig live en neem je gewoon contant geld aan.", + "billingNote": "Je pakket wordt gefactureerd vanaf de dag dat het startte. Staan de kaartbetalingen bij je eerste factuur nog steeds uit, vraag het ons dan even; die maand crediteren we.", + "nextStep": "Als het zover is krijg je van Stripe één kort formulier: je geboortedatum, een telefoonnummer en akkoord met hun voorwaarden. Die link sturen we je zodra jij aan de beurt bent; een Stripe-link blijft maar een paar minuten geldig, dus bewaren heeft geen zin." }, "invoice": { "title": "Factuur", diff --git a/messages/tr.json b/messages/tr.json index f457521..8100ad6 100644 --- a/messages/tr.json +++ b/messages/tr.json @@ -1012,7 +1012,7 @@ "rateLabel": "Oran (baz puan, 100 = %1)", "rateHint": "örn. 150 = %1,50. Tavan {max} baz puan.", "notEligibleRegistryUnavailable": "Tenant kaydı okunamadığı için komisyon uygunluğu şu anda kontrol edilemiyor.", - "notEligibleNotPaired": "Bu tenant'ın kayıt girişi hem online-payments hem de bir stripe_account içermiyor — provizyon, bu ikili olmadan sıfırın üzerindeki bir oranı veritabanından önce reddeder. Her ikisi de olmadan komisyon kapalı kalır.", + "notEligibleNotPaired": "Bu kiracının registry kaydında online-payments ile stripe_account birlikte yok — provisioning bu çift olmadan sıfırdan büyük bir oranı, hem de veritabanından önce reddeder. Stripe hesabını artık biz açıyoruz; eksikse öneri onu oluşturamamıştır (nedeni PR'ında yazar) ya da kayıt daha eskidir. İkisi de gelene kadar komisyon kapalı kalır.", "submit": "Kaydet", "saving": "Kaydediliyor…", "prOpened": "Kayıt PR'si açıldı — birleştirin, ardından tenant'ı yeniden sağlayın.", @@ -1222,18 +1222,18 @@ "rateLabel": "Oran (baz puan, 100 = %1)", "rateHint": "örn. 150 = %1,50. Tavan {max} baz puan.", "notEligibleRegistryUnavailable": "Bu müşterinin kurulumunu şu anda kontrol edemiyoruz, bu yüzden komisyon şimdilik kapalı kalıyor.", - "notEligibleNotPaired": "Komisyon için bu müşterinin çevrimiçi ödeme modülüne ve kendi Stripe hesabına sahip olması gerekir. İkisini de bizden isteyin, bu seçenek açılsın.", + "notEligibleNotPaired": "Komisyon için bu müşterinin online-payments modülü ve bir Stripe hesabı olmalı. O hesabı onlar için biz açıyoruz; eksikse bizim tarafımızda bir şey ters gitmiş demektir — bize söyleyin, bu anahtar açılsın.", "submit": "Kaydet", "saving": "Kaydediliyor…", "prOpened": "SofraPiwas'a gönderildi. Müşterinizin uygulamasına uygulayıp onaylayacağız — ödeme ekranlarında henüz bir şey değişmedi.", "alreadySet": "Müşterinizin uygulaması zaten bu oranı kullanıyor. Gönderilecek bir şey yok." }, "paymentsPending": { - "kicker": "Kartlı ödeme", - "title": "Kartlı ödemeniz yolda", - "body": "Paketinize kartlı ödeme dahil. Sizin için açıyoruz — şu anda yapmanız gereken bir şey yok, kasanızda göründüğü anda size haber vereceğiz. O zamana kadar restoranınız tamamen yayında ve her zamanki gibi nakit alıyor.", - "billingNote": "Paketiniz başladığı günden itibaren faturalandırılır. İlk faturanız geldiğinde kartlı ödeme hâlâ açılmadıysa bize söyleyin, o ayı alacağınıza geçirelim.", - "stripeLink": "Stripe panonuz" + "kicker": "Kartlı ödemeler", + "title": "Kartlı ödemeleriniz yolda", + "body": "Kartlı ödemeler paketinize dahil. Stripe hesabını sizin için biz açıyoruz; yani şu anda yapmanız gereken bir şey yok ve kart kasanızda görünür görünmez size haber vereceğiz. O zamana kadar restoranınız tümüyle yayında ve her zamanki gibi nakit alıyor.", + "billingNote": "Paketiniz başladığı günden itibaren faturalanır. İlk faturanız geldiğinde kartlı ödemeler hâlâ açılmadıysa bize söyleyin, o ayı alacağınıza yazalım.", + "nextStep": "Sırası geldiğinde Stripe size kısa bir form gösterecek: doğum tarihiniz, bir telefon numarası ve koşullarını kabul etmeniz. O bağlantıyı sırası gelince biz göndeririz; Stripe bağlantısı yalnızca birkaç dakika geçerlidir, saklamanın bir anlamı yoktur." }, "invoice": { "title": "Fatura", diff --git a/next.config.ts b/next.config.ts index 554d841..32e7297 100644 --- a/next.config.ts +++ b/next.config.ts @@ -75,6 +75,19 @@ const nextConfig: NextConfig = { source: "/:path*", headers: securityHeaders, }, + // The one route whose URL *is* a credential (E4): the path segment is a + // 32-byte token that lets its holder open this restaurant's Stripe + // onboarding. The site-wide policy above sends the ORIGIN cross-origin, + // which is already safe — but this page redirects to Stripe and may one day + // render HTML with a link on it, and at that moment `strict-origin-...` + // would still send the full URL SAME-origin and the whole answer would hinge + // on nobody adding an outbound link. `no-referrer` costs nothing and does + // not depend on that. Last match wins in Next's header merge, so this + // overrides the entry above for these paths only. + { + source: "/:locale/onboarding/payments/:token", + headers: [{ key: "Referrer-Policy", value: "no-referrer" }], + }, ]; }, }; diff --git a/tests/e2e/owner-payments-pending.spec.ts b/tests/e2e/owner-payments-pending.spec.ts index fc8a116..2c3db64 100644 --- a/tests/e2e/owner-payments-pending.spec.ts +++ b/tests/e2e/owner-payments-pending.spec.ts @@ -55,8 +55,13 @@ test.describe("the buyer is told about the module they cannot see yet", () => { const card = page.getByText(/card payments are on their way/i); await expect(card).toBeVisible(); - // The link the slice specifies — one, outbound, to Stripe's own dashboard. - await expect(page.locator('a[href="https://dashboard.stripe.com"]')).toBeVisible(); + // NO outbound Stripe link, and that is the ADR-011 amendment rather than an + // omission: under Express a restaurant has no full Stripe dashboard to log + // into, and in THIS state the account does not exist at all, so the old + // `https://dashboard.stripe.com` pointed at a login they could not use. + // What replaced it is prose saying what the short form will ask for. + await expect(page.locator('a[href="https://dashboard.stripe.com"]')).toHaveCount(0); + await expect(page.getByText(/short form/i)).toBeVisible(); // Q3's answer (option B), the same policy the public FAQ states: billed from // activation, credited on request. It must be ON this card, not only in the FAQ — diff --git a/tests/unit/payments-pending.test.ts b/tests/unit/payments-pending.test.ts index 58d9eb2..f27fa88 100644 --- a/tests/unit/payments-pending.test.ts +++ b/tests/unit/payments-pending.test.ts @@ -73,8 +73,12 @@ describe("the P4 card's copy rule (§9 Q1)", () => { const card = strings(locale); // Guard against a vacuous pass: an empty or missing namespace would satisfy every // assertion below without a single string being checked. + // `stripeLink` was replaced by `nextStep` under the ADR-011 amendment: an + // Express restaurant has no full Stripe dashboard to link to, and in THIS + // state they have no account at all, so the old pointed at a login they + // could not use. The sentence it carried is re-stated as prose. expect(Object.keys(card).sort()).toEqual( - ["billingNote", "body", "kicker", "stripeLink", "title"], + ["billingNote", "body", "kicker", "nextStep", "title"], ); for (const [key, value] of Object.entries(card)) { expect(value.length, `${locale}.${key} is empty`).toBeGreaterThan(0);