This commit is contained in:
Benjamin Beganović 2021-03-17 16:12:25 +01:00
parent 81f5808bf6
commit 127c6cb3cd
10 changed files with 170 additions and 50 deletions

View File

@ -0,0 +1,47 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\DataMapper\Billing;
class WebhookConfiguration
{
/**
* @var string
*/
public $return_url = '';
/**
* @var string
*/
public $post_purchase_url = '';
/**
* @var array
*/
public $post_purchase_headers = [];
/**
* @var string
*/
public $post_purchase_body = '';
/**
* @var array
*/
public static $casts = [
'return_url' => 'string',
'post_purchase_url' => 'string',
'post_purchase_headers' => 'array',
'post_purchase_body' => 'object',
];
}

View File

@ -29,6 +29,7 @@ use App\Utils\Traits\MakesHash;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Str;
use Illuminate\View\View;
@ -237,11 +238,18 @@ class PaymentController extends Controller
->get();
}
$hash_data = ['invoices' => $payable_invoices->toArray(), 'credits' => $credit_totals];
if ($request->query('hash')) {
$hash_data['billing_context'] = Cache::get($request->query('hash'));
}
$payment_hash = new PaymentHash;
$payment_hash->hash = Str::random(128);
$payment_hash->data = ['invoices' => $payable_invoices->toArray(), 'credits' => $credit_totals];
$payment_hash->data = $hash_data;
$payment_hash->fee_total = $fee_totals;
$payment_hash->fee_invoice_id = $first_invoice->id;
$payment_hash->save();
$totals = [

View File

@ -7,6 +7,7 @@ use App\Models\ClientContact;
use App\Repositories\ClientContactRepository;
use App\Repositories\ClientRepository;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Livewire\Component;
class BillingPortalPurchase extends Component
@ -42,6 +43,8 @@ class BillingPortalPurchase extends Component
public $invoice;
public $coupon;
public function authenticate()
{
$this->validate();
@ -88,8 +91,6 @@ class BillingPortalPurchase extends Component
protected function getPaymentMethods(ClientContact $contact): self
{
// Cache::put($this->hash, ['email' => $this->email ?? $this->contact->email, 'url' => url()->current()]);
$this->steps['fetched_payment_methods'] = true;
$this->methods = $contact->client->service()->getPaymentMethods(1000);
@ -120,7 +121,7 @@ class BillingPortalPurchase extends Component
'key' => '',
'client_contact_id' => $this->contact->hashed_id,
]],
'user_input_promo_code' => '', // Field to input the promo code,
'user_input_promo_code' => $this->coupon,
'quantity' => 1, // Option to increase quantity
];
@ -131,9 +132,21 @@ class BillingPortalPurchase extends Component
->markSent()
->save();
Cache::put($this->hash, [
'email' => $this->email ?? $this->contact->email,
'client_id' => $this->contact->client->id,
'invoice_id' => $this->invoice->id],
now()->addMinutes(60)
);
$this->emit('beforePaymentEventsCompleted');
}
public function applyCouponCode()
{
dd('Applying coupon code: ' . $this->coupon);
}
public function render()
{
if ($this->contact instanceof ClientContact) {

View File

@ -21,6 +21,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Notifications\Notification;
use Laracasts\Presenter\PresentableTrait;
use Illuminate\Support\Facades\Cache;
class Company extends BaseModel
{
@ -342,12 +343,13 @@ class Company extends BaseModel
return null;
}
/**
* @return BelongsTo
*/
public function currency()
{
return $this->belongsTo(Currency::class);
$currencies = Cache::get('currencies');
return $currencies->filter(function ($item) {
return $item->id == $this->settings->currency_id;
})->first();
}
/**

View File

@ -30,6 +30,7 @@ use App\Models\Invoice;
use App\Models\Payment;
use App\Models\PaymentHash;
use App\Models\SystemLog;
use App\Services\BillingSubscription\BillingSubscriptionService;
use App\Utils\Ninja;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\SystemLogTrait;
@ -240,6 +241,8 @@ class BaseDriver extends AbstractPaymentDriver
event(new PaymentWasCreated($payment, $payment->company, Ninja::eventVars()));
BillingSubscriptionService::completePurchase($this->payment_hash);
return $payment->service()->applyNumber()->save();
}

View File

@ -15,6 +15,7 @@ use App\DataMapper\InvoiceItem;
use App\Factory\InvoiceFactory;
use App\Models\BillingSubscription;
use App\Models\ClientSubscription;
use App\Models\PaymentHash;
use App\Models\Product;
use App\Repositories\InvoiceRepository;
@ -107,4 +108,14 @@ class BillingSubscriptionService
{
//scan for any notification we are required to send
}
public static function completePurchase(PaymentHash $payment_hash)
{
if (!property_exists($payment_hash, 'billing_context')) {
return;
}
// At this point we have some state carried from the billing page
// to this, available as $payment_hash->data->billing_context. Make something awesome ⭐
}
}

View File

@ -11,6 +11,7 @@
namespace App\Utils;
use App\Models\Company;
use App\Models\Currency;
/**
@ -88,12 +89,12 @@ class Number
* Formats a given value based on the clients currency AND country.
*
* @param floatval $value The number to be formatted
* @param $client
* @param $entity
* @return string The formatted value
*/
public static function formatMoney($value, $client) :string
public static function formatMoney($value, $entity) :string
{
$currency = $client->currency();
$currency = $entity->currency();
$thousand = $currency->thousand_separator;
$decimal = $currency->decimal_separator;
@ -101,29 +102,38 @@ class Number
$code = $currency->code;
$swapSymbol = $currency->swap_currency_symbol;
// App\Models\Client::country() returns instance of BelongsTo.
// App\Models\Company::country() returns record for the country, that's why we check for the instance.
if ($entity instanceof Company) {
$country = $entity->country();
} else {
$country = $entity->country;
}
/* Country settings override client settings */
if (isset($client->country->thousand_separator) && strlen($client->country->thousand_separator) >= 1) {
$thousand = $client->country->thousand_separator;
if (isset($country->thousand_separator) && strlen($country->thousand_separator) >= 1) {
$thousand = $country->thousand_separator;
}
if (isset($client->country->decimal_separator) && strlen($client->country->decimal_separator) >= 1) {
$decimal = $client->country->decimal_separator;
if (isset($country->decimal_separator) && strlen($country->decimal_separator) >= 1) {
$decimal = $country->decimal_separator;
}
if (isset($client->country->swap_currency_symbol) && strlen($client->country->swap_currency_symbol) >= 1) {
$swapSymbol = $client->country->swap_currency_symbol;
if (isset($country->swap_currency_symbol) && strlen($country->swap_currency_symbol) >= 1) {
$swapSymbol = $country->swap_currency_symbol;
}
$value = number_format($value, $precision, $decimal, $thousand);
$symbol = $currency->symbol;
if ($client->getSetting('show_currency_code') === true && $currency->code == 'CHF') {
if ($entity->getSetting('show_currency_code') === true && $currency->code == 'CHF') {
return "{$code} {$value}";
} elseif ($client->getSetting('show_currency_code') === true) {
} elseif ($entity->getSetting('show_currency_code') === true) {
return "{$value} {$code}";
} elseif ($swapSymbol) {
return "{$value} ".trim($symbol);
} elseif ($client->getSetting('show_currency_code') === false) {
} elseif ($entity->getSetting('show_currency_code') === false) {
return "{$symbol}{$value}";
} else {
return self::formatValue($value, $currency);

2
public/css/app.css vendored

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
{
"/js/app.js": "/js/app.js?id=696e8203d5e8e7cf5ff5",
"/css/app.css": "/css/app.css?id=8d3e488939aa216c7a1c",
"/css/app.css": "/css/app.css?id=e8d6d5e8cb60bc2f15b3",
"/js/clients/invoices/action-selectors.js": "/js/clients/invoices/action-selectors.js?id=a09bb529b8e1826f13b4",
"/js/clients/invoices/payment.js": "/js/clients/invoices/payment.js?id=8ce8955ba775ea5f47d1",
"/js/clients/linkify-urls.js": "/js/clients/linkify-urls.js?id=0dc8c34010d09195d2f7",

View File

@ -1,19 +1,21 @@
<div class="grid grid-cols-12">
<!-- Left side with payment/product information. -->
<div class="col-span-12 lg:col-span-6 bg-gray-50 shadow-lg lg:h-screen flex flex-col items-center">
<div class="w-full p-10 lg:w-1/2 lg:mt-48 lg:p-0">
<h1 class="text-3xl font-bold tracking-wide">Summary</h1>
<p class="text-gray-800 tracking-wide text-sm">A brief overview of the order</p>
<img class="h-8" src="{{ $billing_subscription->company->present()->logo }}"
alt="{{ $billing_subscription->company->present()->name }}">
<p class="my-6">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Culpa earum eos explicabo labore
laboriosam numquam officia pariatur recusandae repellat. Aliquam aliquid amet dignissimos facere iste,
provident sed voluptas! Consequuntur ea expedita magnam maiores nisi rem saepe suscipit. At autem,
expedita explicabo fugiat ipsam maiores modi, odit quae quia quos, voluptatum!</p>
<h1 id="billing-page-company-logo" class="text-3xl font-bold tracking-wide mt-8">
{{ $billing_subscription->product->product_key }}
</h1>
<span class="text-sm uppercase font-bold">Total:</span>
<h1 class="text-2xl font-bold tracking-wide">$4,000</h1>
<p class="my-6">{{ $billing_subscription->product->notes }}</p>
<a href="#" class="block mt-16 inline-flex items-center space-x-2">
<span class="text-sm uppercase font-bold">{{ ctrans('texts.total') }}:</span>
<h1 class="text-2xl font-bold tracking-wide">{{ App\Utils\Number::formatMoney($billing_subscription->product->price, $billing_subscription->company) }}</h1>
@if(auth('contact')->user())
<a href="{{ route('client.invoices.index') }}" class="block mt-16 inline-flex items-center space-x-2">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
class="feather feather-arrow-left">
@ -21,8 +23,9 @@
<polyline points="12 19 5 12 12 5"></polyline>
</svg>
<span>Go back</span>
<span>{{ ctrans('texts.client_portal') }}</span>
</a>
@endif
</div>
</div>
@ -59,7 +62,7 @@
@foreach($this->methods as $method)
<button
wire:click="handleMethodSelectingEvent('{{ $method['company_gateway_id'] }}', '{{ $method['gateway_type_id'] }}')"
class="p-4 border rounded mr-4 hover:border-blue-600">
class="px-3 py-2 border rounded mr-4 hover:border-blue-600">
{{ $method['label'] }}
</button>
@endforeach
@ -69,7 +72,7 @@
@csrf
<label for="email_address">
<span class="input-label">E-mail address</span>
<span class="input-label">{{ ctrans('texts.email_address') }}</span>
<input wire:model.defer="email" type="email" class="input w-full"/>
@error('email')
@ -81,7 +84,7 @@
@if($steps['existing_user'])
<label for="password" class="block mt-2">
<span class="input-label">Password</span>
<span class="input-label">{{ ctrans('texts.password') }}</span>
<input wire:model.defer="password" type="password" class="input w-full" autofocus/>
@error('password')
@ -92,9 +95,32 @@
</label>
@endif
<button type="submit" class="button button-block bg-primary text-white mt-4">Next</button>
<button type="submit"
class="button button-block bg-primary text-white mt-4">{{ ctrans('texts.next') }}</button>
</form>
@endif
<div class="relative mt-8">
<div class="absolute inset-0 flex items-center">
<div class="w-full border-t border-gray-300"></div>
</div>
<div class="relative flex justify-center text-sm leading-5">
<span class="px-2 text-gray-700 bg-white">Have a coupon code?</span>
</div>
</div>
<form wire:submit.prevent="applyCouponCode" class="mt-4">
@csrf
<div class="flex items-center">
<label class="w-full mr-2">
<input type="text" wire:model.defer="coupon" class="input w-full m-0" />
</label>
<button class="button bg-primary m-0 text-white">{{ ctrans('texts.apply') }}</button>
</div>
</form>
</div>
</div>
</div>