Merge pull request #8001 from turbo124/v5-develop

v5.5.43
This commit is contained in:
David Bomba 2022-11-29 22:10:23 +11:00 committed by GitHub
commit bf07742caa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 132 additions and 89 deletions

View File

@ -1 +1 @@
5.5.42
5.5.43

View File

@ -41,6 +41,7 @@ use App\Models\Vendor;
use App\Models\VendorContact;
use App\Repositories\InvoiceRepository;
use App\Utils\Ninja;
use App\Utils\Traits\AppSetup;
use App\Utils\Traits\GeneratesCounter;
use App\Utils\Traits\MakesHash;
use Carbon\Carbon;
@ -53,7 +54,7 @@ use Illuminate\Support\Str;
class DemoMode extends Command
{
use MakesHash, GeneratesCounter;
use MakesHash, GeneratesCounter, AppSetup;
protected $signature = 'ninja:demo-mode';
@ -83,34 +84,14 @@ class DemoMode extends Command
$cached_tables = config('ninja.cached_tables');
foreach ($cached_tables as $name => $class) {
if (! Cache::has($name)) {
// check that the table exists in case the migration is pending
if (! Schema::hasTable((new $class())->getTable())) {
continue;
}
if ($name == 'payment_terms') {
$orderBy = 'num_days';
} elseif ($name == 'fonts') {
$orderBy = 'sort_order';
} elseif (in_array($name, ['currencies', 'industries', 'languages', 'countries', 'banks'])) {
$orderBy = 'name';
} else {
$orderBy = 'id';
}
$tableData = $class::orderBy($orderBy)->get();
if ($tableData->count()) {
Cache::forever($name, $tableData);
}
}
}
$this->info('Migrating');
Artisan::call('migrate:fresh --force');
$this->info('Seeding');
Artisan::call('db:seed --force');
$this->buildCache(true);
$this->info('Seeding Random Data');
$this->createSmallAccount();

View File

@ -185,7 +185,7 @@ class InvoiceFilters extends QueryFilters
* @param string sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort) : Builder
public function sort(string $sort = '') : Builder
{
$sort_col = explode('|', $sort);

View File

@ -539,7 +539,7 @@ class BaseController extends Controller
$query->where('bank_integrations.user_id', $user->id);
}
},
'company.bank_transaction_rules'=> function ($query) use ($updated_at, $user) {
'company.bank_transaction_rules'=> function ($query) use ($user) {
if (! $user->isAdmin()) {
$query->where('bank_transaction_rules.user_id', $user->id);

View File

@ -44,7 +44,7 @@ class StoreBankIntegrationRequest extends Request
{
$input = $this->all();
if(!array_key_exists('provider_name', $input) || strlen($input['provider_name']) == 0)
if(!array_key_exists('provider_name', $input) || strlen($input['provider_name']) == 0 && array_key_exists('bank_account_name', $input))
$input['provider_name'] = $input['bank_account_name'];
$this->replace($input);

View File

@ -15,6 +15,7 @@ use App\Http\Requests\Request;
use App\Http\ValidationRules\ValidCompanyGatewayFeesAndLimitsRule;
use App\Models\Gateway;
use App\Utils\Traits\CompanyGatewayFeesAndLimitsSaver;
use Illuminate\Validation\Rule;
class StoreCompanyGatewayRequest extends Request
{
@ -33,7 +34,7 @@ class StoreCompanyGatewayRequest extends Request
public function rules()
{
$rules = [
'gateway_key' => 'required|alpha_num',
'gateway_key' => ['required','alpha_num',Rule::exists('gateways','key')],
'fees_and_limits' => new ValidCompanyGatewayFeesAndLimitsRule(),
];

View File

@ -62,8 +62,15 @@ class AutoBillCron
nlog($auto_bill_partial_invoices->count().' partial invoices to auto bill');
$auto_bill_partial_invoices->cursor()->each(function ($invoice) {
AutoBill::dispatch($invoice->id, false);
$auto_bill_partial_invoices->chunk(100, function ($invoices) {
foreach($invoices as $invoice)
{
AutoBill::dispatch($invoice->id, false);
}
sleep(2);
});
$auto_bill_invoices = Invoice::whereDate('due_date', '<=', now())
@ -79,8 +86,15 @@ class AutoBillCron
nlog($auto_bill_invoices->count().' full invoices to auto bill');
$auto_bill_invoices->cursor()->each(function ($invoice) {
AutoBill::dispatch($invoice->id, false);
$auto_bill_invoices->chunk(100, function ($invoices) {
foreach($invoices as $invoice)
{
AutoBill::dispatch($invoice->id, false);
}
sleep(2);
});
} else {
//multiDB environment, need to
@ -100,8 +114,14 @@ class AutoBillCron
nlog($auto_bill_partial_invoices->count()." partial invoices to auto bill db = {$db}");
$auto_bill_partial_invoices->cursor()->each(function ($invoice) use ($db) {
AutoBill::dispatch($invoice->id, $db);
$auto_bill_partial_invoices->chunk(100, function ($invoices) use($db){
foreach($invoices as $invoice)
{
AutoBill::dispatch($invoice->id, $db);
}
sleep(2);
});
$auto_bill_invoices = Invoice::whereDate('due_date', '<=', now())
@ -117,10 +137,15 @@ class AutoBillCron
nlog($auto_bill_invoices->count()." full invoices to auto bill db = {$db}");
$auto_bill_invoices->cursor()->each(function ($invoice) use ($db) {
nlog($this->counter);
AutoBill::dispatch($invoice->id, $db);
$this->counter++;
$auto_bill_invoices->chunk(100, function ($invoices) use($db){
foreach($invoices as $invoice)
{
AutoBill::dispatch($invoice->id, $db);
}
sleep(2);
});
}

View File

@ -148,7 +148,7 @@ class ReminderJob implements ShouldQueue
(Ninja::isSelfHost() || $invoice->company->account->isPaidHostedClient())) {
$invoice->invitations->each(function ($invitation) use ($invoice, $reminder_template) {
EmailEntity::dispatch($invitation, $invitation->company, $reminder_template);
EmailEntity::dispatch($invitation, $invitation->company, $reminder_template)->delay(now()->addSeconds(3));
nlog("Firing reminder email for invoice {$invoice->number} - {$reminder_template}");
});

View File

@ -29,8 +29,6 @@ class InvoiceFailedEmailNotification
use UserNotifies, Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $delay = 10;
public function __construct()
{
}

View File

@ -331,7 +331,7 @@ class ACH
$data = [
'gateway_type_id' => $cgt->gateway_type_id,
'payment_type' => PaymentType::ACH,
'transaction_reference' => $response->charges->data[0]->id,
'transaction_reference' => isset($response->latest_charge) ? $response->latest_charge : $response->charges->data[0]->id,
'amount' => $amount,
];

View File

@ -135,7 +135,7 @@ class BrowserPay implements MethodInterface
'payment_method' => $gateway_response->payment_method,
'payment_type' => PaymentType::parseCardType(strtolower($payment_method->card->brand)),
'amount' => $this->stripe->convertFromStripeAmount($gateway_response->amount, $this->stripe->client->currency()->precision, $this->stripe->client->currency()),
'transaction_reference' => optional($payment_intent->charges->data[0])->id,
'transaction_reference' => isset($payment_intent->latest_charge) ? $payment_intent->latest_charge : $payment_intent->charges->data[0]->id,
'gateway_type_id' => GatewayType::APPLE_PAY,
];

View File

@ -141,20 +141,27 @@ class Charge
$payment_method_type = PaymentType::SEPA;
$status = Payment::STATUS_PENDING;
} else {
$payment_method_type = $response->charges->data[0]->payment_method_details->card->brand;
if(isset($response->latest_charge)) {
$charge = \Stripe\Charge::retrieve($response->latest_charge, $this->stripe->stripe_connect_auth);
$payment_method_type = $charge->payment_method_details->card->brand;
}
elseif(isset($response->charges->data[0]->payment_method_details->card->brand))
$payment_method_type = $response->charges->data[0]->payment_method_details->card->brand;
else
$payment_method_type = 'visa';
$status = Payment::STATUS_COMPLETED;
}
if($response?->status == 'processing'){
//allows us to jump over the next stage - used for SEPA
}elseif($response?->status != 'succeeded'){
if(!in_array($response?->status, ['succeeded', 'processing'])){
$this->stripe->processInternallyFailedPayment($this->stripe, new \Exception('Auto billing failed.',400));
}
$data = [
'gateway_type_id' => $cgt->gateway_type_id,
'payment_type' => $this->transformPaymentTypeToConstant($payment_method_type),
'transaction_reference' => $response->charges->data[0]->id,
'transaction_reference' => isset($response->latest_charge) ? $response->latest_charge : $response->charges->data[0]->id,
'amount' => $amount,
];
@ -162,6 +169,7 @@ class Charge
$payment->meta = $cgt->meta;
$payment->save();
$payment_hash->data = array_merge((array) $payment_hash->data, ['payment_intent' => $response, 'amount_with_fee' => $amount]);
$payment_hash->payment_id = $payment->id;
$payment_hash->save();

View File

@ -267,6 +267,39 @@ class PaymentIntentWebhook implements ShouldQueue
}
}
// private function updateSepaPayment($payment_hash, $client, $meta)
// {
// $company_gateway = CompanyGateway::find($this->company_gateway_id);
// $payment_method_type = GatewayType::SEPA;
// $driver = $company_gateway->driver($client)->init()->setPaymentMethod($payment_method_type);
// $payment_hash->data = array_merge((array) $payment_hash->data, $this->stripe_request);
// $payment_hash->save();
// $driver->setPaymentHash($payment_hash);
// $data = [
// 'payment_method' => $payment_hash->data->object->payment_method,
// 'payment_type' => PaymentType::parseCardType(strtolower($meta['card_details'])) ?: PaymentType::CREDIT_CARD_OTHER,
// 'amount' => $payment_hash->data->amount_with_fee,
// 'transaction_reference' => $meta['transaction_reference'],
// 'gateway_type_id' => GatewayType::CREDIT_CARD,
// ];
// $payment = $driver->createPayment($data, Payment::STATUS_COMPLETED);
// SystemLogger::dispatch(
// ['response' => $this->stripe_request, 'data' => $data],
// SystemLog::CATEGORY_GATEWAY_RESPONSE,
// SystemLog::EVENT_GATEWAY_SUCCESS,
// SystemLog::TYPE_STRIPE,
// $client,
// $client->company,
// );
// }
private function updateCreditCardPayment($payment_hash, $client, $meta)
{

View File

@ -660,14 +660,22 @@ class StripePaymentDriver extends BaseDriver
], $this->stripe_connect_auth);
if ($charge->captured) {
$payment = Payment::query()
->where('transaction_reference', $transaction['payment_intent'])
->where('company_id', $request->getCompany()->id)
->where(function ($query) use ($transaction) {
$query->where('transaction_reference', $transaction['payment_intent'])
->orWhere('transaction_reference', $transaction['id']);
})
->first();
$payment = false;
if(isset($transaction['payment_intent']))
{
$payment = Payment::query()
->where('transaction_reference', $transaction['payment_intent'])
->where('company_id', $request->getCompany()->id)
->first();
}
elseif(isset($transaction['id'])) {
$payment = Payment::query()
->where('transaction_reference', $transaction['id'])
->where('company_id', $request->getCompany()->id)
->first();
}
if ($payment) {
$payment->status_id = Payment::STATUS_COMPLETED;

View File

@ -31,32 +31,16 @@ use Illuminate\Support\Facades\Cache;
class BankMatchingService implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, GeneratesCounter;
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
private Company $company;
public function __construct(protected int $company_id, private string $db){}
private $invoices;
public $deleteWhenMissingModels = true;
public function __construct(private int $company_id, private string $db){}
public function handle()
public function handle() :void
{
MultiDB::setDb($this->db);
$this->company = Company::find($this->company_id);
$this->matchTransactions();
}
private function matchTransactions()
{
BankTransaction::where('company_id', $this->company->id)
BankTransaction::where('company_id', $this->company_id)
->where('status_id', BankTransaction::STATUS_UNMATCHED)
->cursor()
->each(function ($bt){
@ -64,11 +48,11 @@ class BankMatchingService implements ShouldQueue
(new BankService($bt))->processRules();
});
}
public function middleware()
{
return [new WithoutOverlapping($this->company_id)];
return [new WithoutOverlapping("bank_match_rate:{$this->company_id}")];
}
}

View File

@ -45,7 +45,7 @@ class SendEmail
$this->credit->invitations->each(function ($invitation) {
if (! $invitation->contact->trashed() && $invitation->contact->email) {
EmailEntity::dispatch($invitation, $invitation->company, $this->reminder_template);
EmailEntity::dispatch($invitation, $invitation->company, $this->reminder_template)->delay(2);
}
});

View File

@ -112,8 +112,7 @@ class AddGatewayFee extends AbstractService
$this->invoice
->client
->service()
->updateBalance($adjustment)
->save();
->updateBalance($adjustment);
$this->invoice
->ledger()

View File

@ -36,7 +36,7 @@ class LedgerService
$this->entity->company_ledger()->save($company_ledger);
ClientLedgerBalanceUpdate::dispatch($this->entity->company, $this->entity->client)->delay(now()->addSeconds(300));
ClientLedgerBalanceUpdate::dispatch($this->entity->company, $this->entity->client)->delay(now()->addSeconds(rand(30,300)));
return $this;
}
@ -52,7 +52,7 @@ class LedgerService
$this->entity->company_ledger()->save($company_ledger);
ClientLedgerBalanceUpdate::dispatch($this->entity->company, $this->entity->client)->delay(now()->addSeconds(300));
ClientLedgerBalanceUpdate::dispatch($this->entity->company, $this->entity->client)->delay(now()->addSeconds(rand(30,300)));
return $this;
}
@ -68,7 +68,7 @@ class LedgerService
$this->entity->company_ledger()->save($company_ledger);
ClientLedgerBalanceUpdate::dispatch($this->entity->company, $this->entity->client)->delay(now()->addSeconds(300));
ClientLedgerBalanceUpdate::dispatch($this->entity->company, $this->entity->client)->delay(now()->addSeconds(rand(30,300)));
return $this;
}

View File

@ -37,7 +37,7 @@ class SendEmail
$contact = $this->payment->client->contacts()->first();
if ($contact?->email)
EmailPayment::dispatch($this->payment, $this->payment->company, $contact);
EmailPayment::dispatch($this->payment, $this->payment->company, $contact)->delay(now()->addSeconds(3));
}
}

View File

@ -70,7 +70,7 @@ trait Inviteable
$qr = $writer->writeString($this->getPaymentLink(), 'utf-8');
return "<svg viewBox='0 0 200 200' width='200' height='200' x='0' y='0' xmlns='http://www.w3.org/2000/svg'>
return "<svg class='pqrcode' viewBox='0 0 200 200' width='200' height='200' x='0' y='0' xmlns='http://www.w3.org/2000/svg'>
<rect x='0' y='0' width='100%'' height='100%' />{$qr}</svg>";
}

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.42',
'app_tag' => '5.5.42',
'app_version' => '5.5.43',
'app_tag' => '5.5.43',
'minimum_client_version' => '5.0.16',
'terms_version' => '1.0.1',
'api_secret' => env('API_SECRET', ''),

View File

@ -4,9 +4,12 @@ use App\Models\Currency;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use App\Utils\Traits\AppSetup;
return new class extends Migration
{
use AppSetup;
/**
* Run the migrations.
*
@ -65,6 +68,9 @@ return new class extends Migration
\Illuminate\Support\Facades\Artisan::call('ninja:design-update');
$this->buildCache(true);
}
/**