mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Merge pull request #8246 from turbo124/v5-develop
Fixes for vendor imports using CSV
This commit is contained in:
commit
87f843dd7d
@ -1 +1 @@
|
|||||||
5.5.65
|
5.5.66
|
@ -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')]);
|
||||||
}
|
}
|
||||||
|
@ -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())
|
||||||
|
@ -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');
|
||||||
|
|
||||||
|
@ -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,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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 {
|
||||||
|
@ -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')
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
|
@ -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()
|
||||||
|
@ -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'));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -271,6 +271,7 @@ class CreditService
|
|||||||
|
|
||||||
public function restoreCredit()
|
public function restoreCredit()
|
||||||
{
|
{
|
||||||
|
|
||||||
$this->credit
|
$this->credit
|
||||||
->client
|
->client
|
||||||
->service()
|
->service()
|
||||||
|
@ -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) {
|
||||||
|
@ -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',
|
||||||
|
@ -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) ?: ' ', 'label' => ($this->entity->is_amount_discount) ? ctrans('texts.discount') : ctrans('texts.discount').' '.$this->entity->discount.'%'];
|
$data['$invoice.discount'] = ['value' => Number::formatMoney($this->entity_calc->getTotalDiscount(), $this->client) ?: ' ', '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) ?: ' ', 'label' => ctrans('texts.subtotal')];
|
$data['$subtotal'] = ['value' => Number::formatMoney($this->entity_calc->getSubTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.subtotal')];
|
||||||
$data['$gross_subtotal'] = ['value' => Number::formatMoney($this->entity_calc->getGrossSubTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.subtotal')];
|
$data['$gross_subtotal'] = ['value' => Number::formatMoney($this->entity_calc->getGrossSubTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.subtotal')];
|
||||||
|
@ -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', ''),
|
||||||
|
@ -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>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user