Merge pull request #8048 from turbo124/v5-stable

v5.5.47
This commit is contained in:
David Bomba 2022-12-07 18:00:52 +11:00 committed by GitHub
commit 1849e0d749
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 224576 additions and 223102 deletions

View File

@ -13,7 +13,7 @@ jobs:
strategy:
matrix:
operating-system: ['ubuntu-20.04', 'ubuntu-22.04']
php-versions: ['8.1.11']
php-versions: ['8.1']
phpunit-versions: ['latest']
env:

View File

@ -1 +1 @@
5.5.46
5.5.47

View File

@ -153,6 +153,21 @@ class BankTransactionFilters extends QueryFilters
{
$sort_col = explode('|', $sort);
if(!is_array($sort_col))
return $this->builder;
if($sort_col[0] == 'deposit')
return $this->builder->where('base_type', 'CREDIT')->orderBy('amount', $sort_col[1]);
if($sort_col[0] == 'withdrawal')
return $this->builder->where('base_type', 'DEBIT')->orderBy('amount', $sort_col[1]);
if($sort_col[0] == 'status')
$sort_col[0] = 'status_id';
if(in_array($sort_col[0],['invoices','expense']))
return $this->builder;
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
}

View File

@ -11,6 +11,7 @@
namespace App\Http\Livewire;
use App\DataMapper\ClientSettings;
use App\Factory\ClientFactory;
use App\Jobs\Mail\NinjaMailerJob;
use App\Jobs\Mail\NinjaMailerObject;
@ -19,15 +20,17 @@ use App\Mail\ContactPasswordlessLogin;
use App\Models\Client;
use App\Models\ClientContact;
use App\Models\Invoice;
use App\Models\RecurringInvoice;
use App\Models\Subscription;
use App\Repositories\ClientContactRepository;
use App\Repositories\ClientRepository;
use App\Utils\Number;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use App\DataMapper\ClientSettings;
use Livewire\Component;
class BillingPortalPurchasev2 extends Component
@ -179,6 +182,13 @@ class BillingPortalPurchasev2 extends Component
*/
public $campaign;
public $bundle;
public $recurring_products;
public $products;
public $optional_recurring_products;
public $optional_products;
public $total;
public function mount()
{
MultiDB::setDb($this->company->db);
@ -196,46 +206,156 @@ class BillingPortalPurchasev2 extends Component
elseif(strlen($this->subscription->promo_code) == 0 && $this->subscription->promo_discount > 0){
$this->price = $this->subscription->promo_price;
}
$this->recurring_products = $this->subscription->service()->recurring_products();
$this->products = $this->subscription->service()->products();
$this->optional_recurring_products = $this->subscription->service()->optional_recurring_products();
$this->optional_products = $this->subscription->service()->optional_products();
// $this->buildBundle();
$this->bundle = collect();
}
public function updatingData()
public function buildBundle()
{
nlog('updating');
// nlog($this->data);
$this->bundle = collect();
$data = $this->data;
foreach($this->recurring_products as $key => $p)
{
$qty = isset($data[$key]['recurring_qty']) ? $data[$key]['recurring_qty'] : 1;
$total = $p->price * $qty;
$this->bundle->push([
'product' => nl2br(substr($p->notes, 0, 50)),
'price' => Number::formatMoney($total, $this->subscription->company).' / '. RecurringInvoice::frequencyForKey($this->subscription->frequency_id),
'total' => $total,
'qty' => $qty,
'is_recurring' => true
]);
}
foreach($this->products as $key => $p)
{
$qty = 1;
$total = $p->price * $qty;
$this->bundle->push([
'product' => nl2br(substr($p->notes, 0, 50)),
'price' => Number::formatMoney($total, $this->subscription->company),
'total' => $total,
'qty' => $qty,
'is_recurring' => false
]);
}
foreach($this->data as $key => $value)
{
if(isset($this->data[$key]['optional_recurring_qty']))
{
$p = $this->optional_recurring_products->first(function ($v,$k) use($key){
return $k == $key;
});
$qty = isset($this->data[$key]['optional_recurring_qty']) ? $this->data[$key]['optional_recurring_qty'] : 0;
$total = $p->price * $qty;
if($qty == 0)
return;
$this->bundle->push([
'product' => nl2br(substr($p->notes, 0, 50)),
'price' => Number::formatMoney($total, $this->subscription->company).' / '. RecurringInvoice::frequencyForKey($this->subscription->frequency_id),
'total' => $total,
'qty' => $qty,
'is_recurring' => true
]);
}
if(isset($this->data[$key]['optional_qty']))
{
$p = $this->optional_products->first(function ($v,$k) use($key){
return $k == $key;
});
$qty = isset($this->data[$key]['optional_qty']) ? $this->data[$key]['optional_qty'] : 0;
$total = $p->price * $qty;
if($qty == 0)
return;
$this->bundle->push([
'product' => nl2br(substr($p->notes, 0, 50)),
'price' => Number::formatMoney($total, $this->subscription->company),
'total' => $total,
'qty' => $qty,
'is_recurring' => false
]);
}
}
$this->total = Number::formatMoney($this->bundle->sum('total'), $this->subscription->company);
return $this;
}
public function updatedData()
{
nlog('updated');
nlog($this->data);
$validatedData = $this->validate();
nlog( $validatedData );
}
public function updating($prop)
{
// $this->resetValidation($prop);
// $this->resetErrorBag($prop);
}
public function updated($propertyName)
{
nlog("validating {$propertyName}");
$this->errors = $this->validateOnly($propertyName);
$x = $this->validateOnly($propertyName, $this->rules(), [], $this->attributes());
nlog($this->errors);
$validatedData = $this->validate();
nlog( $validatedData );
// // $validatedData = $this->validate();
$this->buildBundle();
// $order_validator = Validator::make($this->all(), $this->rules(), [], $this->attributes());
}
public function rules()
{
$rules = [
'email' => ['required', 'email'],
'data' => ['required', 'array'],
'data.*.recurring_qty' => ['required', 'between:100,1000'],
'data.*.optional_recurring_qty' => ['required', 'between:100,1000'],
'data.*.optional_qty' => ['required', 'between:100,1000'],
'data.*.recurring_qty' => 'numeric|between:0,1000',
'data.*.optional_recurring_qty' => 'numeric|between:0,1000',
'data.*.optional_qty' => 'numeric|between:0,1000',
];
return $rules;
}
public function attributes()
{
$attributes = [
'data.*.recurring_qty' => 'recurring_qty',
'data.*.optional_recurring_qty' => 'optional_recurring_qty',
'data.*.optional_qty' => 'optional_qty',
];
return $attributes;
}
public function store()
{
}
/**
* Handle user authentication
*

View File

@ -389,6 +389,7 @@ class MatchBankTransactions implements ShouldQueue
$this->bt->invoice_ids = collect($invoices)->pluck('hashed_id')->implode(',');
$this->bt->status_id = BankTransaction::STATUS_CONVERTED;
$this->bt->payment_id = $payment->id;
$this->bt->save();
}

View File

@ -50,7 +50,7 @@ class QuoteViewedActivity implements ShouldQueue
$fields->user_id = $event->invitation->quote->user_id;
$fields->company_id = $event->invitation->company_id;
$fields->activity_type_id = Activity::VIEW_QUOTE;
$fields->client_id = $event->invitation->client_id;
$fields->client_id = $event->invitation->quote->client_id;
$fields->client_contact_id = $event->invitation->client_contact_id;
$fields->invitation_id = $event->invitation->id;
$fields->quote_id = $event->invitation->quote_id;

View File

@ -126,6 +126,8 @@ class Company extends BaseModel
'report_include_deleted',
'invoice_task_lock',
'use_vendor_currency',
'convert_payment_currency',
'convert_expense_currency',
];
protected $hidden = [

View File

@ -154,31 +154,6 @@ class PaymentIntentWebhook implements ShouldQueue
'card_details' => isset($charge['payment_method_details']['card']['brand']) ? $charge['payment_method_details']['card']['brand'] : PaymentType::CREDIT_CARD_OTHER
];
if(isset($pi['allowed_source_types']) && in_array('card', $pi['allowed_source_types']))
{
$invoice = Invoice::with('client')->find($payment_hash->fee_invoice_id);
$client = $invoice->client;
$this->updateCreditCardPayment($payment_hash, $client, $meta);
}
elseif(isset($pi['payment_method_types']) && in_array('card', $pi['payment_method_types']))
{
$invoice = Invoice::with('client')->find($payment_hash->fee_invoice_id);
$client = $invoice->client;
$this->updateCreditCardPayment($payment_hash, $client, $meta);
}
elseif(isset($pi['payment_method_types']) && in_array('us_bank_account', $pi['payment_method_types']))
{
$invoice = Invoice::with('client')->find($payment_hash->fee_invoice_id);
$client = $invoice->client;
$this->updateAchPayment($payment_hash, $client, $meta);
}
SystemLogger::dispatch(
['response' => $this->stripe_request, 'data' => []],
SystemLog::CATEGORY_GATEWAY_RESPONSE,
@ -188,6 +163,39 @@ class PaymentIntentWebhook implements ShouldQueue
$company,
);
if(isset($pi['allowed_source_types']) && in_array('card', $pi['allowed_source_types']))
{
$invoice = Invoice::with('client')->withTrashed()->find($payment_hash->fee_invoice_id);
$client = $invoice->client;
if($invoice->is_deleted)
return;
$this->updateCreditCardPayment($payment_hash, $client, $meta);
}
elseif(isset($pi['payment_method_types']) && in_array('card', $pi['payment_method_types']))
{
$invoice = Invoice::with('client')->withTrashed()->find($payment_hash->fee_invoice_id);
$client = $invoice->client;
if($invoice->is_deleted)
return;
$this->updateCreditCardPayment($payment_hash, $client, $meta);
}
elseif(isset($pi['payment_method_types']) && in_array('us_bank_account', $pi['payment_method_types']))
{
$invoice = Invoice::with('client')->withTrashed()->find($payment_hash->fee_invoice_id);
$client = $invoice->client;
if($invoice->is_deleted)
return;
$this->updateAchPayment($payment_hash, $client, $meta);
}
}

View File

@ -190,6 +190,8 @@ class CompanyTransformer extends EntityTransformer
'report_include_deleted' => (bool) $company->report_include_deleted,
'invoice_task_lock' => (bool) $company->invoice_task_lock,
'use_vendor_currency' => (bool) $company->use_vendor_currency,
'convert_payment_currency' => (bool) $company->convert_payment_currency,
'convert_expense_currency' => (bool) $company->convert_expense_currency,
];
}

View File

@ -60,7 +60,7 @@ trait GeneratesCounter
$counter_entity = $client;
} elseif ((strpos($pattern, 'groupCounter') !== false) || (strpos($pattern, 'group_counter') !== false)) {
if (property_exists($client->group_settings, $counter_string)) {
if (property_exists($client, 'group_settings') && property_exists($client->group_settings, $counter_string)) {
$counter = $client->group_settings->{$counter_string};
} else {
$counter = 1;
@ -751,7 +751,7 @@ trait GeneratesCounter
$replace[] = $client->number;
$search[] = '{$client_id_number}';
$replace[] = $client->id_number;
$replace[] = $client->id_number ?: $client->number;
$search[] = '{$clientIdNumber}';
$replace[] = $client->id_number ?: $client->number;

View File

@ -14,8 +14,8 @@ return [
'require_https' => env('REQUIRE_HTTPS', true),
'app_url' => rtrim(env('APP_URL', ''), '/'),
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
'app_version' => '5.5.46',
'app_tag' => '5.5.46',
'app_version' => '5.5.47',
'app_tag' => '5.5.47',
'minimum_client_version' => '5.0.16',
'terms_version' => '1.0.1',
'api_secret' => env('API_SECRET', ''),

View File

@ -0,0 +1,31 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('companies', function (Blueprint $table) {
$table->boolean('convert_payment_currency')->default(false);
$table->boolean('convert_expense_currency')->default(false);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
}
};

View File

@ -13,8 +13,8 @@ const RESOURCES = {
"canvaskit/canvaskit.wasm": "bf50631470eb967688cca13ee181af62",
"favicon.png": "dca91c54388f52eded692718d5a98b8b",
"flutter.js": "f85e6fb278b0fd20c349186fb46ae36d",
"/": "e8fe42dfc27768e2bfecaf2d28b81697",
"main.dart.js": "a978830815af17dceb19ce64377f2fd4",
"/": "0aeec408abadedb4253a27508695a379",
"main.dart.js": "503d36721f7b04009003485f545593c2",
"favicon.ico": "51636d3a390451561744c42188ccd628",
"assets/NOTICES": "1a34e70168d56fad075adfb4bdbb20eb",
"assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "b62641afc9ab487008e996a5c5865e56",

217717
public/main.dart.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

213301
public/main.foss.dart.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -7,10 +7,12 @@
{{ $subscription->name }}
</h1>
</div>
<form wire:submit.prevent="submit">
<!-- Recurring Plan Products-->
<ul role="list" class="-my-6 divide-y divide-gray-200">
@if(!empty($subscription->recurring_product_ids))
@foreach($subscription->service()->recurring_products() as $index => $product)
@foreach($recurring_products as $index => $product)
<li class="flex py-6">
@if(false)
<div class="h-24 w-24 flex-shrink-0 overflow-hidden rounded-md border border-gray-200">
@ -32,18 +34,11 @@
<p class="text-gray-500 w-full"></p>
<div class="flex place-content-end">
<p class="text-sm font-light text-gray-700 text-right mr-2 mt-2">{{ ctrans('texts.qty') }}</p>
<input wire:model="data.{{ $index }}.recurring_qty" type="text" class="w-1/4 rounded-md border-gray-300 shadow-sm sm:text-sm text-center" placeholder="0"/>
<input wire:model.debounce.300ms="data.{{ $index }}.recurring_qty" type="text" class="w-1/4 rounded-md border-gray-300 shadow-sm sm:text-sm text-center" placeholder="0"/>
</div>
@endif
</div>
{{ isset($data[$index]['recurring_qty']) ? $data[$index]['recurring_qty'] : 'merp' }}
@if($errors)
@foreach($errors as $error)
{{ $error }}
@endforeach
@endif
@error('data.{{$index}}.recurring_qty')
@error("data.{$index}.recurring_qty")
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative" role="alert">
<span class="block sm:inline">{{ $message }} </span>
<span class="absolute top-0 bottom-0 right-0 px-4 py-3">
@ -55,7 +50,7 @@
@endif
<!-- One Time Plan Products-->
@if(!empty($subscription->product_ids))
@foreach($subscription->service()->products() as $product)
@foreach($products as $product)
<li class="flex py-6">
@if(false)
<div class="h-24 w-24 flex-shrink-0 overflow-hidden rounded-md border border-gray-200">
@ -93,7 +88,7 @@
<!-- Optional Recurring Products-->
<ul role="list" class="-my-6 divide-y divide-gray-200">
@if(!empty($subscription->optional_recurring_product_ids))
@foreach($subscription->service()->optional_recurring_products() as $index => $product)
@foreach($optional_recurring_products as $index => $product)
<li class="flex py-6">
@if(false)
<div class="h-24 w-24 flex-shrink-0 overflow-hidden rounded-md border border-gray-200 mr-2">
@ -104,7 +99,7 @@
<div>
<div class="flex justify-between text-base font-medium text-gray-900">
<h3>{!! nl2br($product->notes) !!}</h3>
<p class="ml-0">{{ \App\Utils\Number::formatMoney($product->price, $subscription->company) }}</p>
<p class="ml-0">{{ \App\Utils\Number::formatMoney($product->price, $subscription->company) }} </p>
</div>
<p class="mt-1 text-sm text-gray-500"></p>
</div>
@ -112,21 +107,22 @@
<p class="text-gray-500 w-full"></p>
<div class="flex place-content-end">
<p class="text-sm font-light text-gray-700 text-right mr-2 mt-2">{{ ctrans('texts.qty') }}</p>
<input wire:model="data.{{ $index }}.optional_recurring_qty" type="text" class="w-1/4 rounded-md border-gray-300 shadow-sm sm:text-sm text-center" placeholder="0"/>
<input wire:model.debounce.300ms="data.{{ $index }}.optional_recurring_qty" type="text" class="w-1/4 rounded-md border-gray-300 shadow-sm sm:text-sm text-center" placeholder="0"/>
</div>
</div>
@error("data.{$index}.optional_recurring_qty")
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative" role="alert">
<span class="block sm:inline">{{ isset($data[$index]['optional_recurring_qty']) ? $data[$index]['optional_recurring_qty'] : '' }}</span>
<span class="block sm:inline">{{ $message }} </span>
<span class="absolute top-0 bottom-0 right-0 px-4 py-3">
</div>
@enderror
</div>
</li>
@endforeach
@endif
@if(!empty($subscription->optional_product_ids))
@foreach($subscription->service()->optional_products() as $index => $product)
@foreach($optional_products as $index => $product)
<li class="flex py-6">
@if(false)
<div class="h-24 w-24 flex-shrink-0 overflow-hidden rounded-md border border-gray-200 mr-2">
@ -145,13 +141,15 @@
<p class="text-gray-500 w-full"></p>
<div class="flex place-content-end">
<p class="text-sm font-light text-gray-700 text-right mr-2 mt-2">{{ ctrans('texts.qty') }}</p>
<input type="text" wire:model="data.{{ $index }}.optional_qty" class="w-1/4 rounded-md border-gray-300 shadow-sm sm:text-sm text-center" placeholder="0">
<input type="text" wire:model.debounce.300ms="data.{{ $index }}.optional_qty" class="w-1/4 rounded-md border-gray-300 shadow-sm sm:text-sm text-center" placeholder="0">
</div>
</div>
@error("data.{$index}.optional_qty")
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative" role="alert">
<span class="block sm:inline">{{ isset($data[$index]['optional_qty']) ? $data[$index]['optional_qty'] : '' }}</span>
<span class="block sm:inline">{{ $message }} </span>
<span class="absolute top-0 bottom-0 right-0 px-4 py-3">
</div>
@enderror
</div>
</li>
@endforeach
@ -160,27 +158,20 @@
</div>
</div>
</form>
<div class="col-span-4 bg-blue-500 flex flex-col item-center p-2 h-screen">
<div class="col-span-4 bg-blue-500 flex flex-col item-center p-2 h-screen" wire:init="buildBundle">
<div class="w-full p-4">
<div id="summary" class="px-4 text-white">
<h1 class="font-semibold text-2xl border-b-2 border-gray-200 border-opacity-50 pb-2 text-white">{{ ctrans('texts.order') }}</h1>
@foreach($subscription->service()->recurring_products() as $product)
@foreach($bundle as $item)
<div class="flex justify-between mt-1 mb-1">
<span class="font-light text-sm uppercase">{!! nl2br(substr($product->notes, 0, 50)) !!}</span>
<span class="font-semibold text-sm">{{ \App\Utils\Number::formatMoney($product->price, $subscription->company) }}</span>
<span class="font-light text-sm uppercase">{{$item['product']}} x {{$item['qty']}}</span>
<span class="font-semibold text-sm">{{ $item['price'] }}</span>
</div>
@endforeach
@foreach($subscription->service()->products() as $product)
<div class="flex justify-between mt-1 mb-1">
<span class="font-light text-sm uppercase">{!! nl2br(substr($product->notes, 0, 50)) !!}</span>
<span class="font-semibold text-sm">{{ \App\Utils\Number::formatMoney($product->price, $subscription->company) }}</span>
</div>
@endforeach
@if(!empty($subscription->promo_code) && !$subscription->trial_enabled)
<form wire:submit.prevent="handleCoupon" class="">
@csrf
@ -190,7 +181,7 @@
<div class="relative flex flex-grow items-stretch focus-within:z-10">
<div class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
</div>
<input type="text" wire:model.defer="coupon" class="block w-full rounded-none rounded-l-md border-gray-300 pl-10 focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" placeholder="">
<input type="text" wire:model.debounce.300ms="coupon" class="block w-full rounded-none rounded-l-md border-gray-300 pl-10 focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" placeholder="">
</div>
<button type="button" class="relative -ml-px inline-flex items-center space-x-2 rounded-r-md border border-gray-300 bg-gray-50 px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-100 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500">
@ -204,7 +195,7 @@
<div class="border-t-2 border-gray-200 border-opacity-50 mt-8">
<div class="flex font-semibold justify-between py-6 text-sm uppercase">
<span>{{ ctrans('texts.total') }}</span>
<span>{{ \App\Utils\Number::formatMoney($price, $subscription->company) }}</span>
<span>{{ $total }}</span>
</div>
<button class="bg-white font-semibold hover:bg-gray-600 py-3 text-sm text-blue-500 uppercase w-full">Checkout</button>
</div>

View File

@ -95,7 +95,7 @@
<input type="checkbox" class="form-checkbox cursor-pointer" onchange="appendToElement('multiple-downloads', '{{ $document->hashed_id }}')" />
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-500">
{{ Illuminate\Support\Str::limit($document->name, 20) }}
{{ Illuminate\Support\Str::limit($document->name, 40) }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-500">