Merge pull request #8246 from turbo124/v5-develop

Fixes for vendor imports using CSV
This commit is contained in:
David Bomba 2023-02-05 14:56:31 +11:00 committed by GitHub
commit 87f843dd7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 83 additions and 37 deletions

View File

@ -1 +1 @@
5.5.65 5.5.66

View File

@ -149,12 +149,18 @@ class PaymentController extends Controller
$payment = $payment->service()->applyCredits($payment_hash)->save(); $payment = $payment->service()->applyCredits($payment_hash)->save();
$invoices = Invoice::whereIn('id', $this->transformKeys(array_column($payment_hash->invoices(), 'invoice_id'))); $invoices = Invoice::whereIn('id', $this->transformKeys(array_column($payment_hash->invoices(), 'invoice_id')));
$invoices->each(function ($i){
$i->is_proforma = false;
$i->saveQuietly();
});
event('eloquent.created: App\Models\Payment', $payment); event('eloquent.created: App\Models\Payment', $payment);
if($invoices->sum('balance') > 0){ if($invoices->sum('balance') > 0){
$invoice = $invoices->first(); $invoice = $invoices->first();
$invoice->service()->touchPdf(true);
return redirect()->route('client.invoice.show', ['invoice' => $invoice->hashed_id, 'hash' => $request->input('hash')]); return redirect()->route('client.invoice.show', ['invoice' => $invoice->hashed_id, 'hash' => $request->input('hash')]);
} }

View File

@ -494,7 +494,7 @@ class CompanyController extends BaseController
$account->delete(); $account->delete();
if (Ninja::isHosted()) { if (Ninja::isHosted()) {
\Modules\Admin\Jobs\Account\NinjaDeletedAccount::dispatch($account_key, $request->all()); \Modules\Admin\Jobs\Account\NinjaDeletedAccount::dispatch($account_key, $request->all(), auth()->user()->email);
} }
LightLogs::create(new AccountDeleted()) LightLogs::create(new AccountDeleted())

View File

@ -52,6 +52,7 @@ class InvoicesTable extends Component
$query = Invoice::query() $query = Invoice::query()
->where('company_id', $this->company->id) ->where('company_id', $this->company->id)
->where('is_deleted', false) ->where('is_deleted', false)
->where('is_proforma', false)
->with('client.gateway_tokens', 'client.contacts') ->with('client.gateway_tokens', 'client.contacts')
->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc'); ->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc');

View File

@ -227,6 +227,8 @@ class BaseImport
]; ];
nlog("Ingest {$ex->getMessage()}"); nlog("Ingest {$ex->getMessage()}");
nlog($record);
} }
} }
@ -368,7 +370,7 @@ class BaseImport
$payment_data['invoices'] = [ $payment_data['invoices'] = [
[ [
'invoice_id' => $invoice->id, 'invoice_id' => $invoice->id,
'amount' => $payment_data['amount'] ?? null, 'amount' => min($invoice->amount, $payment_data['amount']) ?? null,
], ],
]; ];

View File

@ -52,17 +52,6 @@ class VendorTransformer extends BaseTransformer
'custom_value2' => $this->getString($data, 'vendor.custom_value2'), 'custom_value2' => $this->getString($data, 'vendor.custom_value2'),
'custom_value3' => $this->getString($data, 'vendor.custom_value3'), 'custom_value3' => $this->getString($data, 'vendor.custom_value3'),
'custom_value4' => $this->getString($data, 'vendor.custom_value4'), 'custom_value4' => $this->getString($data, 'vendor.custom_value4'),
// 'vendor_contacts' => [
// [
// 'first_name' => $this->getString(
// $data,
// 'vendor.first_name'
// ),
// 'last_name' => $this->getString($data, 'vendor.last_name'),
// 'email' => $this->getString($data, 'vendor.email'),
// 'phone' => $this->getString($data, 'vendor.phone'),
// ],
// ],
'contacts' => [ 'contacts' => [
[ [
'first_name' => $this->getString( 'first_name' => $this->getString(
@ -70,7 +59,7 @@ class VendorTransformer extends BaseTransformer
'contact.first_name' 'contact.first_name'
), ),
'last_name' => $this->getString($data, 'contact.last_name'), 'last_name' => $this->getString($data, 'contact.last_name'),
'email' => $this->getString($data, 'contact.email'), 'email' => strlen($this->getString($data, 'contact.email')) > 1 ? $this->getString($data, 'contact.email') : $this->getString($data, 'vendor.email'),
'phone' => $this->getString($data, 'contact.phone'), 'phone' => $this->getString($data, 'contact.phone'),
'custom_value1' => $this->getString( 'custom_value1' => $this->getString(
$data, $data,

View File

@ -80,7 +80,11 @@ class ZipQuotes implements ShouldQueue
$path = $this->quotes->first()->client->quote_filepath($invitation); $path = $this->quotes->first()->client->quote_filepath($invitation);
$this->quotes->each(function ($quote) { $this->quotes->each(function ($quote) {
$quote->service()->createInvitations();
(new CreateEntityPdf($quote->invitations()->first()))->handle(); (new CreateEntityPdf($quote->invitations()->first()))->handle();
}); });
try { try {

View File

@ -13,6 +13,8 @@ namespace App\Listeners\Subscription;
use App\Libraries\MultiDB; use App\Libraries\MultiDB;
use App\Models\Account; use App\Models\Account;
use App\Models\Company;
use App\Notifications\Ninja\RenewalFailureNotification;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
use Imdhemy\Purchases\Events\AppStore\DidRenew; use Imdhemy\Purchases\Events\AppStore\DidRenew;
@ -38,10 +40,18 @@ class AppStoreRenewSubscription implements ShouldQueue
$inapp_transaction_id = $event->getSubscriptionId(); //$subscription_id $inapp_transaction_id = $event->getSubscriptionId(); //$subscription_id
nlog("inapp upgrade processing for = {$inapp_transaction_id}");
MultiDB::findAndSetDbByInappTransactionId($inapp_transaction_id); MultiDB::findAndSetDbByInappTransactionId($inapp_transaction_id);
$account = Account::where('inapp_transaction_id', $inapp_transaction_id)->first(); $account = Account::where('inapp_transaction_id', $inapp_transaction_id)->first();
if(!$account) {
$ninja_company = Company::on('db-ninja-01')->find(config('ninja.ninja_default_company_id'));
$ninja_company->notification(new RenewalFailureNotification("{$inapp_transaction_id}"))->ninja();
return;
}
if($account->plan_term == 'month') if($account->plan_term == 'month')
$account->plan_expires = now()->addMonth(); $account->plan_expires = now()->addMonth();
elseif($account->plan_term == 'year') elseif($account->plan_term == 'year')

View File

@ -145,7 +145,7 @@ class VendorContact extends Authenticatable implements HasLocalePreference
{ {
return $this return $this
->withTrashed() ->withTrashed()
->company() // ->company()
->where('id', $this->decodePrimaryKey($value)) ->where('id', $this->decodePrimaryKey($value))
->firstOrFail(); ->firstOrFail();
} }

View File

@ -30,13 +30,7 @@ class ClientAccountNotFound extends Notification
* @return void * @return void
*/ */
public function __construct(protected string $account_key, protected string $email){}
protected string $account_key;
public function __construct(string $account_key)
{
$this->account_key = $account_key;
}
/** /**
* Get the notification's delivery channels. * Get the notification's delivery channels.
@ -77,6 +71,7 @@ class ClientAccountNotFound extends Notification
$content = "Client not found, unable to remove account\n"; $content = "Client not found, unable to remove account\n";
$content .= "Account: {$this->account_key }\n"; $content .= "Account: {$this->account_key }\n";
$content .= "Email: {$this->email}\n";
return (new SlackMessage) return (new SlackMessage)
->success() ->success()

View File

@ -68,7 +68,7 @@ class RenewalFailureNotification extends Notification
public function toSlack($notifiable) public function toSlack($notifiable)
{ {
$content = "Plan paid, account not updated\n"; $content = "Plan paid, account not updated\n";
$content .= "Contact: {$this->notification_message}"; $content .= "Contact/Inapp Purchase: {$this->notification_message}";
return (new SlackMessage) return (new SlackMessage)
->success() ->success()

View File

@ -38,9 +38,14 @@ class UserObserver
*/ */
public function updated(User $user) public function updated(User $user)
{ {
// if (Ninja::isHosted() && $user->isDirty('phone')) {
// VerifyPhone::dispatch($user); if (Ninja::isHosted() && $user->isDirty('email') && $user->company_users()->where('is_owner', true)->exists()) {
// } //ensure they are owner user and update email on file.
if(class_exists(\Modules\Admin\Jobs\Account\UpdateOwnerUser::class))
\Modules\Admin\Jobs\Account\UpdateOwnerUser::dispatch($user->account->key, $user, $user->getOriginal('email'));
}
} }
/** /**

View File

@ -99,7 +99,7 @@ class SquarePaymentDriver extends BaseDriver
$amount_money = new \Square\Models\Money(); $amount_money = new \Square\Models\Money();
$amount_money->setAmount($this->convertAmount($amount)); $amount_money->setAmount($this->convertAmount($amount));
$amount_money->setCurrency($this->square_driver->client->currency()->code); $amount_money->setCurrency($this->client->currency()->code);
$body = new \Square\Models\RefundPaymentRequest(\Illuminate\Support\Str::random(32), $amount_money, $payment->transaction_reference); $body = new \Square\Models\RefundPaymentRequest(\Illuminate\Support\Str::random(32), $amount_money, $payment->transaction_reference);

View File

@ -193,7 +193,7 @@ class InstantPayment
$payment_method_id = $this->request->input('payment_method_id'); $payment_method_id = $this->request->input('payment_method_id');
$invoice_totals = $payable_invoices->sum('amount'); $invoice_totals = $payable_invoices->sum('amount');
$first_invoice = $invoices->first(); $first_invoice = $invoices->first();
$credit_totals = $first_invoice->client->getSetting('use_credits_payment') == 'always' ? $first_invoice->client->service()->getCreditBalance() : 0; $credit_totals = in_array($first_invoice->client->getSetting('use_credits_payment'), ['always', 'option']) ? $first_invoice->client->service()->getCreditBalance() : 0;
$starting_invoice_amount = $first_invoice->balance; $starting_invoice_amount = $first_invoice->balance;
/* Schedule a job to check the gateway fees for this invoice*/ /* Schedule a job to check the gateway fees for this invoice*/
@ -297,7 +297,7 @@ class InstantPayment
} }
public function processCreditPayment(Request $request, array $data) public function processCreditPayment(Request $request, array $data)
{ {
return render('gateways.credit.index', $data); return render('gateways.credit.index', $data);
} }
} }

View File

@ -271,6 +271,7 @@ class CreditService
public function restoreCredit() public function restoreCredit()
{ {
$this->credit $this->credit
->client ->client
->service() ->service()

View File

@ -138,7 +138,7 @@ class DeletePayment
private function updateCreditables() private function updateCreditables()
{ {
if ($this->payment->credits()->exists()) { if ($this->payment->credits()->exists()) {
$this->payment->credits()->each(function ($paymentable_credit) { $this->payment->credits()->where('is_deleted',0)->each(function ($paymentable_credit) {
$multiplier = 1; $multiplier = 1;
if ($paymentable_credit->pivot->amount < 0) { if ($paymentable_credit->pivot->amount < 0) {

View File

@ -36,6 +36,7 @@ use App\Models\Subscription;
use App\Models\SystemLog; use App\Models\SystemLog;
use App\Repositories\CreditRepository; use App\Repositories\CreditRepository;
use App\Repositories\InvoiceRepository; use App\Repositories\InvoiceRepository;
use App\Repositories\PaymentRepository;
use App\Repositories\RecurringInvoiceRepository; use App\Repositories\RecurringInvoiceRepository;
use App\Repositories\SubscriptionRepository; use App\Repositories\SubscriptionRepository;
use App\Services\Subscription\ZeroCostProduct; use App\Services\Subscription\ZeroCostProduct;
@ -58,6 +59,8 @@ class SubscriptionService
/** @var subscription */ /** @var subscription */
private $subscription; private $subscription;
private float $credit_payments = 0;
public function __construct(Subscription $subscription) public function __construct(Subscription $subscription)
{ {
$this->subscription = $subscription; $this->subscription = $subscription;
@ -530,13 +533,43 @@ class SubscriptionService
->orderBy('id', 'desc') ->orderBy('id', 'desc')
->first(); ->first();
if($this->calculateProRataRefundForSubscription($last_invoice) > 0) //if last payment was created from a credit, do not generate a new credit, refund the old one.
if($last_invoice) {
$last_invoice->payments->each(function ($payment){
$payment->credits()->where('is_deleted', 0)->each(function ($credit){
$this->credit_payments += $credit->pivot->sum('amount');
});
});
$invoice_repo = new InvoiceRepository();
$invoice_repo->delete($last_invoice);
$payment_repo = new PaymentRepository(new CreditRepository());
$last_invoice->payments->each(function ($payment) use ($payment_repo){
$payment_repo->delete($payment);
});
}
//if there are existing credit payments, then we refund directly to the credit.
if($this->calculateProRataRefundForSubscription($last_invoice) > 0 && $this->credit_payments == 0)
$credit = $this->createCredit($last_invoice, $target_subscription, false); $credit = $this->createCredit($last_invoice, $target_subscription, false);
$new_recurring_invoice = $this->createNewRecurringInvoice($recurring_invoice); $new_recurring_invoice = $this->createNewRecurringInvoice($recurring_invoice);
$invoice = $this->changePlanInvoice($target_subscription, $recurring_invoice->client_id); $invoice = $this->changePlanInvoice($target_subscription, $recurring_invoice->client_id);
$invoice->recurring_id = $new_recurring_invoice->id; $invoice->recurring_id = $new_recurring_invoice->id;
$invoice->is_proforma = false;
$invoice->save(); $invoice->save();
$payment = PaymentFactory::create($invoice->company_id, $invoice->user_id, $invoice->client_id); $payment = PaymentFactory::create($invoice->company_id, $invoice->user_id, $invoice->client_id);
@ -545,7 +578,7 @@ class SubscriptionService
$payment->is_manual = true; $payment->is_manual = true;
$payment->save(); $payment->save();
$payment->service()->applyCreditsToInvoice($invoice); $payment->service()->applyNumber()->applyCreditsToInvoice($invoice);
$context = [ $context = [
'context' => 'change_plan', 'context' => 'change_plan',

View File

@ -296,7 +296,7 @@ class HtmlEngine
$data['$portal_url'] = ['value' => $this->invitation->getPortalLink(), 'label' =>'']; $data['$portal_url'] = ['value' => $this->invitation->getPortalLink(), 'label' =>''];
$data['$entity_number'] = &$data['$number']; $data['$entity_number'] = &$data['$number'];
$data['$invoice.discount'] = ['value' => Number::formatMoney($this->entity_calc->getTotalDiscount(), $this->client) ?: '&nbsp;', 'label' => ($this->entity->is_amount_discount) ? ctrans('texts.discount') : ctrans('texts.discount').'&nbsp'.$this->entity->discount.'&percnt;']; $data['$invoice.discount'] = ['value' => Number::formatMoney($this->entity_calc->getTotalDiscount(), $this->client) ?: '&nbsp;', 'label' => ($this->entity->is_amount_discount) ? ctrans('texts.discount') : ctrans('texts.discount').' '.$this->entity->discount.'%'];
$data['$discount'] = &$data['$invoice.discount']; $data['$discount'] = &$data['$invoice.discount'];
$data['$subtotal'] = ['value' => Number::formatMoney($this->entity_calc->getSubTotal(), $this->client) ?: '&nbsp;', 'label' => ctrans('texts.subtotal')]; $data['$subtotal'] = ['value' => Number::formatMoney($this->entity_calc->getSubTotal(), $this->client) ?: '&nbsp;', 'label' => ctrans('texts.subtotal')];
$data['$gross_subtotal'] = ['value' => Number::formatMoney($this->entity_calc->getGrossSubTotal(), $this->client) ?: '&nbsp;', 'label' => ctrans('texts.subtotal')]; $data['$gross_subtotal'] = ['value' => Number::formatMoney($this->entity_calc->getGrossSubTotal(), $this->client) ?: '&nbsp;', 'label' => ctrans('texts.subtotal')];

View File

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

View File

@ -101,7 +101,7 @@
<div class="mt-4"> <div class="mt-4">
@foreach($subscription->service()->getPlans() as $_subscription) @foreach($subscription->service()->getPlans() as $_subscription)
<button class="mt-8 mr-2"> <button class="mt-8 mr-2">
<a class="border mt-4 bg-white rounded py-2 px-4 hover:bg-gray-100 text-sm" target="_blank" href="{{ route('client.subscription.purchase', $_subscription->hashed_id) }}">{{ $_subscription->name }}</a> <a class="border mt-4 bg-white rounded py-2 px-4 hover:bg-gray-100 text-sm" href="{{ route('client.subscription.purchase', $_subscription->hashed_id) }}">{{ $_subscription->name }}</a>
</button> </button>
@endforeach @endforeach
</div> </div>