Birçok Laravel SaaS iskeletinin temel varsayımı şudur: müşterileriniz ödeme için Stripe kullanıyor.
<p>Bu varsayım, Kahire, Riyad, Dubai, Doha, Kuveyt veya Kuala Lumpur'daki bir işletmeye satış yapmaya çalıştığınızda geçerliliğini kaybediyor; burada insanlar genellikle Paymob, Fawry, HyperPay, MyFatoorah, Telr, HitPay gibi yöntemleri kullanıyor. Aniden, sizin için zaman kazandırması beklenen bu iskelet, gerçek pazarınıza ait hiçbir ödemeyi almayı başaramıyor.</p>
<p>Müşteri projelerinde bu durumla sık sık karşılaştım, bu yüzden sağladığım işlevselliği içeren bir yapı geliştirdim. Buna <strong>Quartz</strong> diyoruz. Bu yapı MIT lisansına sahiptir ve <strong>tek bir arayüz altında 13 ödeme geçidi sunmaktadır</strong>:</p>
<ul>
<li>
<strong>Global</strong> — Stripe, PayPal
</li>
<li>
<strong>Mısır</strong> — Paymob, Fawry, PayTabs, Geidea
</li>
<li>
<strong>GCC</strong> — Amazon Payment Services, Telr, HyperPay, MyFatoorah
</li>
<li>
<strong>Malezya</strong> — HitPay, Billplz, iPay88
</li>
</ul>
<p>→ <strong><a href="https://github.com/Quartz-Solutions/saas" target="_blank" rel="noopener noreferrer">github.com/Quartz-Solutions/saas</a></strong></p>
<p>Ancak ilginç olan kısım liste değil. Bu geçitlerin, ödeme sürecinin nasıl işlediği konusunda <em>hiçbir şeyde</em> anlaşmıyor olmalarıdır — ve bunları uygulama genelinde bir biçim vermek gerçek mühendislik problemini oluşturuyor.</p>
<h2>
<a name="the-problem-13-gateways-5-completely-different-checkout-flows" href="#the-problem-13-gateways-5-completely-different-checkout-flows"></a>
Problem: 13 geçit, 5 tamamen farklı ödeme akışı
</h2>
<p>Bu geçitlerde "bir ödeme başlat" çağrısı yaptığınızda, size döndürülenler şunlardır:</p>
<ul>
<li>
<strong>Stripe / PayPal / PayTabs / MyFatoorah</strong> → tarayıcıyı yönlendireceğiniz bir barındırılan URL.
</li>
<li>
<strong>Paymob</strong> → sayfanıza gömmeniz gereken bir <strong>iframe</strong>.
</li>
<li>
<strong>HyperPay</strong> → DOM'a yerleştirilmiş bir <strong>JavaScript widget</strong> (COPYandPAY).
</li>
<li>
<strong>Amazon Payment Services / iPay88</strong> → bir <strong>self-submitting form POST</strong> olarak render edeceğiniz imzalı alanlar.
</li>
<li>
<strong>Fawry</strong> → müşteri tarafından fiziksel bir kioskta nakit ödeme yapabilmesi için gereken bir <strong>kiosk referans numarası</strong>.
</li>
</ul>
<p>Naif bir iskelet bu durumu her yere sızdırır — denetleyici, her karar için <code>match ($gateway)</code> kullanır ve yeni bir geçit eklemek, kullanıcı arayüzünü on yerde etkilemek anlamına gelir. Bu polimorfizm değil; bir trench coat giymiş etiketli bir birleşimdir.</p>
<h2>
<a name="the-fix-a-discriminated-raw-checkoutresult-endraw-" href="#the-fix-a-discriminated-raw-checkoutresult-endraw-"></a>
Çözüm: ayrıştırılmış bir <code>CheckoutResult</code>
</h2>
<p>Her geçit bir arayüzü uygular:</p>
<div class="highlight js-code-highlight">
<pre class="highlight php"><code><span class="kd">interface</span> <span class="nc">CheckoutGateway</span>{
public function initiateCheckout(CheckoutSession $session): CheckoutResult;
<span class="cd">/ @return array<int string=""> ISO 4217 kodları bu geçit hangi para biriminde işlem yapabilir */</int></span>
<span class="k">public</span> <span class="k">function</span> <span class="n">supportedCurrencies</span><span class="p">():</span> <span class="kt">array</span><span class="p">;</span>
<span class="k">public</span> <span class="k">function</span> <span class="n">supportsSubscriptions</span><span class="p">():</span> <span class="kt">bool</span><span class="p">;</span>}
<p>initiateCheckout() beş bilinen sonuç türünden birini döndürür — ön uç bunun nasıl render edileceğini bilir:</p>
<div class="highlight js-code-highlight">
<pre class="highlight php"><code><span class="k">return</span> <span class="k">new</span> <span class="nc">RedirectCheckout</span><span class="p">(</span><span class="nv">$sessionId</span><span class="p">,</span> <span class="n">url</span><span class="o">:</span> <span class="nv">$stripeSession</span><span class="o">-></span><span class="n">url</span><span class="p">);</span>

