diff --git a/app/Http/Controllers/BaseController.php b/app/Http/Controllers/BaseController.php
index 1d362bd85d1d..e155e65202ff 100644
--- a/app/Http/Controllers/BaseController.php
+++ b/app/Http/Controllers/BaseController.php
@@ -70,6 +70,7 @@ class BaseController extends Controller
'company.clients.contacts',
'company.clients.gateway_tokens',
'company.products',
+ 'company.recurring_invoices',
'company.invoices.invitations.contact',
'company.invoices.invitations.company',
'company.invoices.documents',
@@ -213,6 +214,9 @@ class BaseController extends Controller
'company.products' => function ($query) use ($updated_at) {
$query->where('updated_at', '>=', $updated_at);
},
+ 'company.recurring_invoices'=> function ($query) use ($updated_at) {
+ $query->where('updated_at', '>=', $updated_at)->with('company');
+ },
'company.invoices'=> function ($query) use ($updated_at) {
$query->where('updated_at', '>=', $updated_at)->with('invitations', 'company', 'documents');
},
diff --git a/app/Models/Company.php b/app/Models/Company.php
index 8093ab24bd42..54b9c7d7f928 100644
--- a/app/Models/Company.php
+++ b/app/Models/Company.php
@@ -29,6 +29,7 @@ use App\Models\Language;
use App\Models\Payment;
use App\Models\PaymentType;
use App\Models\Product;
+use App\Models\RecurringInvoice;
use App\Models\TaxRate;
use App\Models\Timezone;
use App\Models\Traits\AccountTrait;
@@ -240,6 +241,14 @@ class Company extends BaseModel
return $this->hasMany(Invoice::class)->withTrashed();
}
+ /**
+ * @return \Illuminate\Database\Eloquent\Relations\HasMany
+ */
+ public function recurring_invoices()
+ {
+ return $this->hasMany(RecurringInvoice::class)->withTrashed();
+ }
+
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
diff --git a/app/PaymentDrivers/Authorize/AuthorizeCreditCard.php b/app/PaymentDrivers/Authorize/AuthorizeCreditCard.php
index 87fca0a08e7e..e154c5c01250 100644
--- a/app/PaymentDrivers/Authorize/AuthorizeCreditCard.php
+++ b/app/PaymentDrivers/Authorize/AuthorizeCreditCard.php
@@ -104,6 +104,9 @@ class AuthorizeCreditCard
$payment = $this->createPaymentRecord($data, $amount);
$payment->meta = $cgt->meta;
$payment->save();
+
+ $payment_hash->payment_id = $payment->id;
+ $payment_hash->save();
$this->authorize->attachInvoices($payment, $payment_hash);
$payment->service()->updateInvoicePayment($payment_hash);
@@ -144,6 +147,9 @@ class AuthorizeCreditCard
$amount = array_sum(array_column($payment_hash->invoices(), 'amount')) + $payment_hash->fee_total;
$payment = $this->createPaymentRecord($data, $amount);
+
+ $payment_hash->payment_id = $payment->id;
+ $payment_hash->save();
$this->authorize->attachInvoices($payment, $payment_hash);
diff --git a/app/PaymentDrivers/CheckoutComPaymentDriver.php b/app/PaymentDrivers/CheckoutComPaymentDriver.php
index ce9dcc2895c2..45ecfd8bd3e0 100644
--- a/app/PaymentDrivers/CheckoutComPaymentDriver.php
+++ b/app/PaymentDrivers/CheckoutComPaymentDriver.php
@@ -67,13 +67,20 @@ class CheckoutComPaymentDriver extends BaseDriver
];
}
- /** Since with Checkout.com we handle only credit cards, this method should be empty. */
- public function setPaymentMethod($string = null)
+ /**
+ * Since with Checkout.com we handle only credit cards, this method should be empty.
+ * @param $string payment_method string
+ */
+ public function setPaymentMethod($payment_method = null)
{
return $this;
}
- public function init()
+ /**
+ * Initialize the checkout payment driver
+ * @return $this
+ */
+ public function init()
{
$config = [
'secret' => $this->company_gateway->getConfigField('secretApiKey'),
@@ -82,8 +89,15 @@ class CheckoutComPaymentDriver extends BaseDriver
];
$this->gateway = new CheckoutApi($config['secret'], $config['sandbox'], $config['public']);
+
+ return $this;
}
+ /**
+ * Process different view depending on payment type
+ * @param int $gateway_type_id The gateway type
+ * @return string The view string
+ */
public function viewForType($gateway_type_id)
{
if ($gateway_type_id == GatewayType::CREDIT_CARD) {
@@ -95,11 +109,23 @@ class CheckoutComPaymentDriver extends BaseDriver
}
}
+ /**
+ * Authorization view
+ *
+ * @param array $data Payment data array
+ * @return view Authorization View
+ */
public function authorizeView($data)
{
return render('gateways.checkout.authorize');
}
+ /**
+ * Payment View
+ *
+ * @param array $data Payment data array
+ * @return view The payment view
+ */
public function processPaymentView(array $data)
{
$data['gateway'] = $this;
@@ -113,6 +139,12 @@ class CheckoutComPaymentDriver extends BaseDriver
return render($this->viewForType($data['payment_method_id']), $data);
}
+ /**
+ * Process the payment response
+ *
+ * @param Request $request The payment request
+ * @return view The payment response view
+ */
public function processPaymentResponse($request)
{
$this->init();
@@ -123,6 +155,7 @@ class CheckoutComPaymentDriver extends BaseDriver
'raw_value' => $request->raw_value,
'currency' => $request->currency,
'payment_hash' =>$request->payment_hash,
+ 'reference' => $request->payment_hash,
];
$state = array_merge($state, $request->all());
@@ -132,10 +165,12 @@ class CheckoutComPaymentDriver extends BaseDriver
$method = new IdSource($state['token']);
$payment = new CheckoutPayment($method, $state['currency']);
$payment->amount = $state['value'];
+ $payment->reference = $state['reference'];
} else {
$method = new TokenSource($state['server_response']->cardToken);
$payment = new CheckoutPayment($method, $state['currency']);
$payment->amount = $state['value'];
+ $payment->reference = $state['reference'];
if ($this->client->currency()->code === 'EUR') {
$payment->{'3ds'} = ['enabled' => true];
@@ -162,6 +197,12 @@ class CheckoutComPaymentDriver extends BaseDriver
}
}
+ /**
+ * Process a successful payment response
+ *
+ * @param array $state The state array
+ * @return view The response
+ */
public function processSuccessfulPayment($state)
{
$state['charge_id'] = $state['payment_response']->id;
@@ -178,6 +219,9 @@ class CheckoutComPaymentDriver extends BaseDriver
$payment = $this->createPayment($data, Payment::STATUS_COMPLETED);
$payment_hash = PaymentHash::whereRaw('BINARY `hash`= ?', [$state['payment_hash']])->firstOrFail();
+ $payment_hash->payment_id = $payment->id;
+ $payment_hash->save();
+
$this->attachInvoices($payment, $payment_hash);
$payment->service()->updateInvoicePayment($payment_hash);
@@ -251,17 +295,19 @@ class CheckoutComPaymentDriver extends BaseDriver
public function processInternallyFailedPayment($e, $state)
{
- $message = json_decode($e->getBody());
+ $error_message = json_decode($e->getBody());
- PaymentFailureMailer::dispatch($this->client, $message->error_type, $this->client->company, $state['value']);
+ PaymentFailureMailer::dispatch($this->client, $error_message->message, $this->client->company, $state['value']);
$message = [
'server_response' => $state['server_response'],
- 'data' => $message,
+ 'data' => $e->getBody(),
];
SystemLogger::dispatch($message, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_CHECKOUT, $this->client);
-
+
+ //todo push to a error page with the exception message.
+
throw new \Exception('Failed to process the payment.', 1);
}
diff --git a/app/PaymentDrivers/PayPalExpressPaymentDriver.php b/app/PaymentDrivers/PayPalExpressPaymentDriver.php
index 76b8600efd63..952410f09688 100644
--- a/app/PaymentDrivers/PayPalExpressPaymentDriver.php
+++ b/app/PaymentDrivers/PayPalExpressPaymentDriver.php
@@ -162,6 +162,10 @@ class PayPalExpressPaymentDriver extends BasePaymentDriver
$payment = $this->createPayment($response->getData());
$payment_hash = PaymentHash::whereRaw('BINARY `hash`= ?', [$request->input('payment_hash')])->firstOrFail();
+
+ $payment_hash->payment_id = $payment->id;
+ $payment_hash->save();
+
$this->attachInvoices($payment, $payment_hash);
$payment->service()->updateInvoicePayment($payment_hash);
diff --git a/app/PaymentDrivers/Stripe/Charge.php b/app/PaymentDrivers/Stripe/Charge.php
index c92b475f9252..4f76dc3e67d5 100644
--- a/app/PaymentDrivers/Stripe/Charge.php
+++ b/app/PaymentDrivers/Stripe/Charge.php
@@ -167,6 +167,9 @@ class Charge
$payment->meta = $cgt->meta;
$payment->save();
+ $payment_hash->payment_id = $payment->id;
+ $payment_hash->save();
+
$this->stripe->attachInvoices($payment, $payment_hash);
$payment->service()->updateInvoicePayment($payment_hash);
diff --git a/app/PaymentDrivers/Stripe/CreditCard.php b/app/PaymentDrivers/Stripe/CreditCard.php
index c52ca0b9e279..af617e791fa2 100644
--- a/app/PaymentDrivers/Stripe/CreditCard.php
+++ b/app/PaymentDrivers/Stripe/CreditCard.php
@@ -197,6 +197,11 @@ class CreditCard
$payment = $this->stripe->createPayment($data, $status = Payment::STATUS_COMPLETED);
$payment->meta = $payment_meta;
+ $payment->save();
+
+ $payment_hash = $state['payment_hash'];
+ $payment_hash->payment_id = $payment->id;
+ $payment_hash->save();
$payment = $this->stripe->attachInvoices($payment, $state['payment_hash']);
diff --git a/app/Services/Payment/UpdateInvoicePayment.php b/app/Services/Payment/UpdateInvoicePayment.php
index ca7ef1119b6a..60eaeb686c8c 100644
--- a/app/Services/Payment/UpdateInvoicePayment.php
+++ b/app/Services/Payment/UpdateInvoicePayment.php
@@ -75,7 +75,9 @@ class UpdateInvoicePayment
->updateBalance($paid_amount * -1)
->save();
+ info("firing invoice was updated event");
event(new InvoiceWasUpdated($invoice, $invoice->company, Ninja::eventVars()));
+ info("fired invoice was updated event");
});
return $this->payment;
diff --git a/app/Transformers/CompanyTransformer.php b/app/Transformers/CompanyTransformer.php
index bd1de6b65de0..c935afef3791 100644
--- a/app/Transformers/CompanyTransformer.php
+++ b/app/Transformers/CompanyTransformer.php
@@ -29,6 +29,7 @@ use App\Models\PaymentTerm;
use App\Models\Product;
use App\Models\Project;
use App\Models\Quote;
+use App\Models\RecurringInvoice;
use App\Models\SystemLog;
use App\Models\Task;
use App\Models\TaxRate;
@@ -40,6 +41,7 @@ use App\Transformers\CompanyTokenTransformer;
use App\Transformers\CreditTransformer;
use App\Transformers\DocumentTransformer;
use App\Transformers\PaymentTermTransformer;
+use App\Transformers\RecurringInvoiceTransformer;
use App\Transformers\SystemLogTransformer;
use App\Transformers\TaskTransformer;
use App\Transformers\WebhookTransformer;
@@ -70,6 +72,7 @@ class CompanyTransformer extends EntityTransformer
'clients',
'contacts',
'invoices',
+ 'recurring_invoices',
'tax_rates',
'products',
'country',
@@ -247,6 +250,13 @@ class CompanyTransformer extends EntityTransformer
return $this->includeCollection($company->invoices, $transformer, Invoice::class);
}
+ public function includeRecurringInvoices(Company $company)
+ {
+ $transformer = new RecurringInvoiceTransformer($this->serializer);
+
+ return $this->includeCollection($company->recurring_invoices, $transformer, RecurringInvoice::class);
+ }
+
public function includeQuotes(Company $company)
{
$transformer = new QuoteTransformer($this->serializer);
diff --git a/app/Transformers/RecurringInvoiceTransformer.php b/app/Transformers/RecurringInvoiceTransformer.php
index 51c01e458e8a..71e5586119eb 100644
--- a/app/Transformers/RecurringInvoiceTransformer.php
+++ b/app/Transformers/RecurringInvoiceTransformer.php
@@ -115,10 +115,10 @@ class RecurringInvoiceTransformer extends EntityTransformer
'footer' => $invoice->footer ?: '',
'partial' => (float) ($invoice->partial ?: 0.0),
'partial_due_date' => $invoice->partial_due_date ?: '',
- 'custom_value1' => (float) $invoice->custom_value1 ?: '',
- 'custom_value2' => (float) $invoice->custom_value2 ?: '',
- 'custom_value3' => (bool) $invoice->custom_value3 ?: '',
- 'custom_value4' => (bool) $invoice->custom_value4 ?: '',
+ 'custom_value1' => (string) $invoice->custom_value1 ?: '',
+ 'custom_value2' => (string) $invoice->custom_value2 ?: '',
+ 'custom_value3' => (string) $invoice->custom_value3 ?: '',
+ 'custom_value4' => (string) $invoice->custom_value4 ?: '',
'has_tasks' => (bool) $invoice->has_tasks,
'has_expenses' => (bool) $invoice->has_expenses,
'custom_surcharge1' => (float) $invoice->custom_surcharge1,
diff --git a/composer.lock b/composer.lock
index e1d3b8c13ee7..267ae13c98ac 100644
--- a/composer.lock
+++ b/composer.lock
@@ -160,16 +160,16 @@
},
{
"name": "aws/aws-sdk-php",
- "version": "3.152.1",
+ "version": "3.153.0",
"source": {
"type": "git",
"url": "https://github.com/aws/aws-sdk-php.git",
- "reference": "65e10d45a3ecfdc112b7efe9f839343179a86879"
+ "reference": "3045bc6c8f7d2521b3e0d4a7b407194af8725c8f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/65e10d45a3ecfdc112b7efe9f839343179a86879",
- "reference": "65e10d45a3ecfdc112b7efe9f839343179a86879",
+ "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/3045bc6c8f7d2521b3e0d4a7b407194af8725c8f",
+ "reference": "3045bc6c8f7d2521b3e0d4a7b407194af8725c8f",
"shasum": ""
},
"require": {
@@ -241,7 +241,7 @@
"s3",
"sdk"
],
- "time": "2020-09-08T18:13:04+00:00"
+ "time": "2020-09-09T18:12:35+00:00"
},
{
"name": "brick/math",
@@ -529,16 +529,16 @@
},
{
"name": "composer/composer",
- "version": "1.10.12",
+ "version": "1.10.13",
"source": {
"type": "git",
"url": "https://github.com/composer/composer.git",
- "reference": "a6cc92b39c796ec3fb9a360f9c0e578afc2fc96d"
+ "reference": "47c841ba3b2d3fc0b4b13282cf029ea18b66d78b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/composer/composer/zipball/a6cc92b39c796ec3fb9a360f9c0e578afc2fc96d",
- "reference": "a6cc92b39c796ec3fb9a360f9c0e578afc2fc96d",
+ "url": "https://api.github.com/repos/composer/composer/zipball/47c841ba3b2d3fc0b4b13282cf029ea18b66d78b",
+ "reference": "47c841ba3b2d3fc0b4b13282cf029ea18b66d78b",
"shasum": ""
},
"require": {
@@ -619,7 +619,7 @@
"type": "tidelift"
}
],
- "time": "2020-09-08T20:58:51+00:00"
+ "time": "2020-09-09T09:46:34+00:00"
},
{
"name": "composer/package-versions-deprecated",
@@ -692,16 +692,16 @@
},
{
"name": "composer/semver",
- "version": "1.6.0",
+ "version": "1.7.0",
"source": {
"type": "git",
"url": "https://github.com/composer/semver.git",
- "reference": "9787c20e39dfeea673665abee0679c73ba67105d"
+ "reference": "114f819054a2ea7db03287f5efb757e2af6e4079"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/composer/semver/zipball/9787c20e39dfeea673665abee0679c73ba67105d",
- "reference": "9787c20e39dfeea673665abee0679c73ba67105d",
+ "url": "https://api.github.com/repos/composer/semver/zipball/114f819054a2ea7db03287f5efb757e2af6e4079",
+ "reference": "114f819054a2ea7db03287f5efb757e2af6e4079",
"shasum": ""
},
"require": {
@@ -763,7 +763,7 @@
"type": "tidelift"
}
],
- "time": "2020-09-08T20:42:08+00:00"
+ "time": "2020-09-09T09:34:06+00:00"
},
{
"name": "composer/spdx-licenses",
@@ -2585,16 +2585,16 @@
},
{
"name": "laravel/framework",
- "version": "v7.28.0",
+ "version": "v7.28.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
- "reference": "5d3b4e3e62294716e3c810be3d2eb1375685b87d"
+ "reference": "f7493ab717ca2a9598b1db2d6a3bae8ac8c755e8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/framework/zipball/5d3b4e3e62294716e3c810be3d2eb1375685b87d",
- "reference": "5d3b4e3e62294716e3c810be3d2eb1375685b87d",
+ "url": "https://api.github.com/repos/laravel/framework/zipball/f7493ab717ca2a9598b1db2d6a3bae8ac8c755e8",
+ "reference": "f7493ab717ca2a9598b1db2d6a3bae8ac8c755e8",
"shasum": ""
},
"require": {
@@ -2739,7 +2739,7 @@
"framework",
"laravel"
],
- "time": "2020-09-08T15:10:40+00:00"
+ "time": "2020-09-09T15:02:46+00:00"
},
{
"name": "laravel/slack-notification-channel",
@@ -2929,16 +2929,16 @@
},
{
"name": "laravel/ui",
- "version": "v2.2.1",
+ "version": "v2.3.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/ui.git",
- "reference": "456daa330a32483b0fa9794334e60af6b2db3bf6"
+ "reference": "2ccaa3b821ea8ac7e05393b946d0578bdb46099b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/ui/zipball/456daa330a32483b0fa9794334e60af6b2db3bf6",
- "reference": "456daa330a32483b0fa9794334e60af6b2db3bf6",
+ "url": "https://api.github.com/repos/laravel/ui/zipball/2ccaa3b821ea8ac7e05393b946d0578bdb46099b",
+ "reference": "2ccaa3b821ea8ac7e05393b946d0578bdb46099b",
"shasum": ""
},
"require": {
@@ -2980,7 +2980,7 @@
"laravel",
"ui"
],
- "time": "2020-09-08T13:09:39+00:00"
+ "time": "2020-09-09T12:07:59+00:00"
},
{
"name": "league/commonmark",
diff --git a/database/migrations/2020_08_18_140557_add_is_public_to_documents_table.php b/database/migrations/2020_08_18_140557_add_is_public_to_documents_table.php
index cc58b5309c1e..73e37c195f27 100644
--- a/database/migrations/2020_08_18_140557_add_is_public_to_documents_table.php
+++ b/database/migrations/2020_08_18_140557_add_is_public_to_documents_table.php
@@ -40,7 +40,11 @@ class AddIsPublicToDocumentsTable extends Migration
$table->decimal('fee_total', 16, 4);
$table->unsignedInteger('fee_invoice_id')->nullable();
$table->mediumText('data');
+ $table->unsignedInteger('payment_id')->nullable();
$table->timestamps(6);
+
+ $table->foreign('payment_id')->references('id')->on('payments')->onDelete('cascade')->onUpdate('cascade');
+
});
Schema::table('recurring_invoices', function ($table) {
diff --git a/resources/views/portal/ninja2020/gateways/checkout/credit_card.blade.php b/resources/views/portal/ninja2020/gateways/checkout/credit_card.blade.php
index 26da86c3b343..0c0f85f5fdd7 100644
--- a/resources/views/portal/ninja2020/gateways/checkout/credit_card.blade.php
+++ b/resources/views/portal/ninja2020/gateways/checkout/credit_card.blade.php
@@ -6,6 +6,7 @@
+
@endpush
@@ -15,6 +16,7 @@
@csrf
+