diff --git a/app/Console/Commands/CreateTestData.php b/app/Console/Commands/CreateTestData.php index 30803cfcd804..4fabbcd4022c 100644 --- a/app/Console/Commands/CreateTestData.php +++ b/app/Console/Commands/CreateTestData.php @@ -331,7 +331,7 @@ class CreateTestData extends Command $this->info('Creating '.$this->count.' clients'); - for ($x = 0; $x < $this->count * 200; $x++) { + for ($x = 0; $x < $this->count * 100; $x++) { $z = $x + 1; $this->info('Creating client # '.$z); diff --git a/app/Filters/DocumentFilters.php b/app/Filters/DocumentFilters.php new file mode 100644 index 000000000000..122545c7269b --- /dev/null +++ b/app/Filters/DocumentFilters.php @@ -0,0 +1,78 @@ +builder->where('client_id', $client_id); + } + + /** + * Filter based on search text. + * + * @param string query filter + * @return Builder + * @deprecated + */ + public function filter(string $filter = '') : Builder + { + if (strlen($filter) == 0) { + return $this->builder; + } + + return $this->builder; + } + + /** + * Sorts the list based on $sort. + * + * @param string sort formatted as column|asc + * @return Builder + */ + public function sort(string $sort) : Builder + { + $sort_col = explode('|', $sort); + + return $this->builder->orderBy($sort_col[0], $sort_col[1]); + } + + /** + * Returns the base query. + * + * @param int company_id + * @param User $user + * @return Builder + * @deprecated + */ + public function baseQuery(int $company_id, User $user) : Builder + { + } + + /** + * Filters the query by the users company ID. + * + * @return Illuminate\Database\Query\Builder + */ + public function entityFilter() + { + return $this->builder->company(); + } +} diff --git a/app/Http/Controllers/BaseController.php b/app/Http/Controllers/BaseController.php index 00f3d6b750c3..68ac5202d06d 100644 --- a/app/Http/Controllers/BaseController.php +++ b/app/Http/Controllers/BaseController.php @@ -65,7 +65,6 @@ class BaseController extends Controller 'company.task_statuses', 'company.expense_categories', 'company.documents', - //'company.users', 'company.users.company_user', 'company.clients.contacts.company', 'company.clients.gateway_tokens', @@ -105,6 +104,7 @@ class BaseController extends Controller 'user.company_user', 'token', 'company.activities', + 'company.documents', //'company.users.company_user', 'company.tax_rates', 'company.groups', @@ -184,7 +184,10 @@ class BaseController extends Controller protected function refreshResponse($query) { - $this->manager->parseIncludes($this->first_load); + if (auth()->user()->getCompany()->is_large) + $this->manager->parseIncludes($this->mini_load); + else + $this->manager->parseIncludes($this->first_load); $this->serializer = request()->input('serializer') ?: EntityTransformer::API_SERIALIZER_ARRAY; @@ -197,9 +200,9 @@ class BaseController extends Controller $transformer = new $this->entity_transformer($this->serializer); $updated_at = request()->has('updated_at') ? request()->input('updated_at') : 0; - if (auth()->user()->getCompany()->is_large && ! request()->has('updated_at')) { - return response()->json(['message' => ctrans('texts.large_account_update_parameter'), 'errors' =>[]], 401); - } + // if (auth()->user()->getCompany()->is_large && ! request()->has('updated_at')) { + // return response()->json(['message' => ctrans('texts.large_account_update_parameter'), 'errors' =>[]], 401); + // } $updated_at = date('Y-m-d H:i:s', $updated_at); diff --git a/app/Http/Controllers/DocumentController.php b/app/Http/Controllers/DocumentController.php index 0fd18e00289e..73ef54f22d5e 100644 --- a/app/Http/Controllers/DocumentController.php +++ b/app/Http/Controllers/DocumentController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers; +use App\Filters\DocumentFilters; use App\Http\Requests\Document\DestroyDocumentRequest; use App\Http\Requests\Document\ShowDocumentRequest; use App\Http\Requests\Document\StoreDocumentRequest; @@ -26,10 +27,6 @@ class DocumentController extends BaseController */ protected $document_repo; - /** - * DocumentController constructor. - * @param DocumentRepository $document_repo - */ public function __construct(DocumentRepository $document_repo) { parent::__construct(); @@ -40,13 +37,46 @@ class DocumentController extends BaseController } /** - * Display a listing of the resource. - * - * @return void + * @OA\Get( + * path="/api/v1/documents", + * operationId="getDocuments", + * tags={"documents"}, + * summary="Gets a list of documents", + * description="Lists documents, search and filters allow fine grained lists to be generated. + + Query parameters can be added to performed more fine grained filtering of the documents, these are handled by the DocumentsFilters class which defines the methods available", + * @OA\Parameter(ref="#/components/parameters/X-Api-Secret"), + * @OA\Parameter(ref="#/components/parameters/X-Api-Token"), + * @OA\Parameter(ref="#/components/parameters/X-Requested-With"), + * @OA\Parameter(ref="#/components/parameters/include"), + * @OA\Parameter(ref="#/components/parameters/index"), + * @OA\Response( + * response=200, + * description="A list of documents", + * @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"), + * @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"), + * @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"), + * @OA\JsonContent(ref="#/components/schemas/Document"), + * ), + * @OA\Response( + * response=422, + * description="Validation error", + * @OA\JsonContent(ref="#/components/schemas/ValidationError"), + * ), + * @OA\Response( + * response="default", + * description="Unexpected Error", + * @OA\JsonContent(ref="#/components/schemas/Error"), + * ), + * ) + * @param DocumentsFilters $filters + * @return Response|mixed */ - public function index() + public function index(DocumentFilters $filters) { - // + $documents = Document::filter($filters); + + return $this->listResponse($documents); } /** diff --git a/app/Jobs/RecurringInvoice/SendRecurring.php b/app/Jobs/RecurringInvoice/SendRecurring.php index 0b3f1b52412d..843c722d1d6c 100644 --- a/app/Jobs/RecurringInvoice/SendRecurring.php +++ b/app/Jobs/RecurringInvoice/SendRecurring.php @@ -80,6 +80,7 @@ class SendRecurring implements ShouldQueue } if ($invoice->client->getSetting('auto_bill_date') == 'on_send_date' && $this->recurring_invoice->auto_bill_enabled) { + nlog("attempting to autobill {$invoice->number}"); $invoice->service()->autoBill()->save(); } diff --git a/app/Mail/Engine/PaymentEmailEngine.php b/app/Mail/Engine/PaymentEmailEngine.php index 61605162569f..7021ecb097eb 100644 --- a/app/Mail/Engine/PaymentEmailEngine.php +++ b/app/Mail/Engine/PaymentEmailEngine.php @@ -57,12 +57,35 @@ class PaymentEmailEngine extends BaseEmailEngine /* Use default translations if a custom message has not been set*/ if (iconv_strlen($body_template) == 0) { - $body_template = trans( - 'texts.payment_message', - ['amount' => $payment->amount, 'company' => $payment->company->present()->name()], - null, - $this->client->locale() - ); + + if ($payment->invoices()->exists()) + { + $invoice_texts = ctrans('texts.invoice_number_short'); + + foreach ($this->payment->invoices as $invoice) { + $invoice_texts .= $invoice->number.','; + } + + $invoice_texts = substr($invoice_texts, 0, -1); + + $body_template = trans( + 'texts.payment_message_extended', + ['amount' => $payment->amount, 'company' => $payment->company->present()->name(), 'invoice' => $invoice_texts], + null, + $this->client->locale() + ); + } + else + { + + $body_template = trans( + 'texts.payment_message', + ['amount' => $payment->amount, 'company' => $payment->company->present()->name()], + null, + $this->client->locale() + ); + } + } if (is_array($this->template_data) && array_key_exists('subject', $this->template_data) && strlen($this->template_data['subject']) > 0) { diff --git a/app/Models/Document.php b/app/Models/Document.php index 59b0f12edd5a..7c0c1565b2cc 100644 --- a/app/Models/Document.php +++ b/app/Models/Document.php @@ -11,12 +11,14 @@ namespace App\Models; +use App\Models\Filterable; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Support\Facades\Storage; class Document extends BaseModel { use SoftDeletes; + use Filterable; const DOCUMENT_PREVIEW_SIZE = 300; // pixels diff --git a/app/Models/Presenters/CompanyPresenter.php b/app/Models/Presenters/CompanyPresenter.php index 0148d1f1adc4..fec12b9eac87 100644 --- a/app/Models/Presenters/CompanyPresenter.php +++ b/app/Models/Presenters/CompanyPresenter.php @@ -91,13 +91,13 @@ class CompanyPresenter extends EntityPresenter } } - public function getSpcQrCode($client_custom, $invoice_number, $balance) + public function getSpcQrCode($client_currency, $invoice_number, $balance) { $settings = $this->entity->settings; return - "SPC\n0200\n1\nCH860021421411198240K\nK\n{$this->name}\n{$settings->address1}\n{$settings->postal_code} {$settings->city}\n\n\nCH\n\n\n\n\n\n\n\n{$balance}\n{$client_custom}\n\n\n\n\n\n\n\nNON\n\n{$invoice_number}\nEPD\n"; + "SPC\n0200\n1\nCH860021421411198240K\nK\n{$this->name}\n{$settings->address1}\n{$settings->postal_code} {$settings->city}\n\n\nCH\n\n\n\n\n\n\n\n{$balance}\n{$client_currency}\n\n\n\n\n\n\n\nNON\n\n{$invoice_number}\nEPD\n"; } } diff --git a/app/PaymentDrivers/Authorize/AuthorizeCreditCard.php b/app/PaymentDrivers/Authorize/AuthorizeCreditCard.php index 76e52594cf9b..10569e081c9f 100644 --- a/app/PaymentDrivers/Authorize/AuthorizeCreditCard.php +++ b/app/PaymentDrivers/Authorize/AuthorizeCreditCard.php @@ -157,7 +157,7 @@ class AuthorizeCreditCard $payment_record = []; $payment_record['amount'] = $amount; $payment_record['payment_type'] = PaymentType::CREDIT_CARD_OTHER; - + $payment_record['gateway_type_id'] = GatewayType::CREDIT_CARD; $payment_record['transaction_reference'] = $response->getTransactionResponse()->getTransId(); $payment = $this->authorize->createPayment($payment_record); @@ -165,21 +165,6 @@ class AuthorizeCreditCard return $payment; } - private function createPaymentRecord($data, $amount) :?Payment - { - $response = $data['response']; - //create a payment record - - $payment = $this->authorize->createPayment($data['response']); - $payment->gateway_type_id = GatewayType::CREDIT_CARD; - $payment->type_id = PaymentType::CREDIT_CARD_OTHER; - $payment->transaction_reference = $response->getTransactionResponse()->getTransId(); - $payment->amount = $amount; - $payment->save(); - - return $payment; - } - private function processSuccessfulResponse($data, $request) { $payment_hash = PaymentHash::whereRaw('BINARY `hash`= ?', [$request->input('payment_hash')])->firstOrFail(); diff --git a/app/PaymentDrivers/BaseDriver.php b/app/PaymentDrivers/BaseDriver.php index a8e5b6e6f343..16f2c3442cb5 100644 --- a/app/PaymentDrivers/BaseDriver.php +++ b/app/PaymentDrivers/BaseDriver.php @@ -209,6 +209,8 @@ class BaseDriver extends AbstractPaymentDriver $payment->currency_id = $this->client->getSetting('currency_id'); $payment->date = Carbon::now(); + //$payment->gateway_type_id = $data['gateway_type_id']; + $client_contact = $this->getContact(); $client_contact_id = $client_contact ? $client_contact->id : null; diff --git a/app/PaymentDrivers/PayPalExpressPaymentDriver.php b/app/PaymentDrivers/PayPalExpressPaymentDriver.php index 387b29c1ce9a..f2ca729fc891 100644 --- a/app/PaymentDrivers/PayPalExpressPaymentDriver.php +++ b/app/PaymentDrivers/PayPalExpressPaymentDriver.php @@ -130,6 +130,7 @@ class PayPalExpressPaymentDriver extends BaseDriver 'payment_type' => PaymentType::PAYPAL, 'amount' => $this->payment_hash->data->amount, 'transaction_reference' => $response->getTransactionReference(), + 'gateway_type_id' => GatewayType::PAYPAL, ]; $payment = $this->createPayment($data, \App\Models\Payment::STATUS_COMPLETED); diff --git a/app/PaymentDrivers/Stripe/ACH.php b/app/PaymentDrivers/Stripe/ACH.php index 0906757c7c31..223a0db7cb59 100644 --- a/app/PaymentDrivers/Stripe/ACH.php +++ b/app/PaymentDrivers/Stripe/ACH.php @@ -157,6 +157,7 @@ class ACH 'payment_type' => PaymentType::ACH, 'amount' => $this->stripe->convertFromStripeAmount($this->stripe->payment_hash->data->amount, $this->stripe->client->currency()->precision), 'transaction_reference' => $state['charge']->id, + 'gateway_type_id' => GatewayType::BANK_TRANSFER, ]; $payment = $this->stripe->createPayment($data, Payment::STATUS_PENDING); diff --git a/app/PaymentDrivers/Stripe/Alipay.php b/app/PaymentDrivers/Stripe/Alipay.php index 518971af37c8..f923c9e2a5de 100644 --- a/app/PaymentDrivers/Stripe/Alipay.php +++ b/app/PaymentDrivers/Stripe/Alipay.php @@ -76,6 +76,8 @@ class Alipay 'payment_type' => PaymentType::ALIPAY, 'amount' => $this->stripe->convertFromStripeAmount($this->stripe->payment_hash->data->stripe_amount, $this->stripe->client->currency()->precision), 'transaction_reference' => $source, + 'gateway_type_id' => GatewayType::ALIPAY, + ]; $payment = $this->stripe->createPayment($data, Payment::STATUS_PENDING); diff --git a/app/PaymentDrivers/Stripe/Charge.php b/app/PaymentDrivers/Stripe/Charge.php index ff62c8675a17..f68c1a693c98 100644 --- a/app/PaymentDrivers/Stripe/Charge.php +++ b/app/PaymentDrivers/Stripe/Charge.php @@ -172,23 +172,18 @@ class Charge $data = [ 'gateway_type_id' => $cgt->gateway_type_id, - 'type_id' => $this->transformPaymentTypeToConstant($payment_method_type), + 'payment_type' => $this->transformPaymentTypeToConstant($payment_method_type), 'transaction_reference' => $response->charges->data[0]->id, + 'amount' => $amount, ]; - $payment = $this->stripe->createPaymentRecord($data, $amount); + $payment = $this->stripe->createPayment($data); $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); - - event(new PaymentWasCreated($payment, $payment->company, Ninja::eventVars())); - return $payment; } diff --git a/app/PaymentDrivers/Stripe/CreditCard.php b/app/PaymentDrivers/Stripe/CreditCard.php index bf05b4ef12e2..48f59eb382cc 100644 --- a/app/PaymentDrivers/Stripe/CreditCard.php +++ b/app/PaymentDrivers/Stripe/CreditCard.php @@ -114,6 +114,7 @@ class CreditCard 'payment_type' => PaymentType::parseCardType(strtolower($stripe_method->card->brand)), 'amount' => $this->stripe->convertFromStripeAmount($this->stripe->payment_hash->data->server_response->amount, $this->stripe->client->currency()->precision), 'transaction_reference' => optional($this->stripe->payment_hash->data->payment_intent->charges->data[0])->id, + 'gateway_type_id' => GatewayType::CREDIT_CARD, ]; diff --git a/app/PaymentDrivers/Stripe/SOFORT.php b/app/PaymentDrivers/Stripe/SOFORT.php index 15726117fa0a..af96cdf1c693 100644 --- a/app/PaymentDrivers/Stripe/SOFORT.php +++ b/app/PaymentDrivers/Stripe/SOFORT.php @@ -82,6 +82,7 @@ class SOFORT 'payment_type' => PaymentType::SOFORT, 'amount' => $this->stripe->convertFromStripeAmount($this->stripe->payment_hash->data->stripe_amount, $this->stripe->client->currency()->precision), 'transaction_reference' => $source, + 'gateway_type_id' => GatewayType::SOFORT, ]; $payment = $this->stripe->createPayment($data, Payment::STATUS_PENDING); diff --git a/app/PaymentDrivers/StripePaymentDriver.php b/app/PaymentDrivers/StripePaymentDriver.php index 1b1681be2647..52b9dc67caf0 100644 --- a/app/PaymentDrivers/StripePaymentDriver.php +++ b/app/PaymentDrivers/StripePaymentDriver.php @@ -175,7 +175,7 @@ class StripePaymentDriver extends BaseDriver return $this->payment_method->paymentView($data); } - public function processPaymentResponse($request) //We never have to worry about unsuccessful payments as failures are handled at the front end for this driver. + public function processPaymentResponse($request) { return $this->payment_method->paymentResponse($request); } @@ -322,34 +322,11 @@ class StripePaymentDriver extends BaseDriver public function tokenBilling(ClientGatewayToken $cgt, PaymentHash $payment_hash) { + $this->setPaymentHash($payment_hash); + return (new Charge($this))->tokenBilling($cgt, $payment_hash); } - /** - * Creates a payment record for the given - * data array. - * - * @param array $data An array of payment attributes - * @param float $amount The amount of the payment - * @return Payment The payment object - */ - public function createPaymentRecord($data, $amount): ?Payment - { - $payment = PaymentFactory::create($this->client->company_id, $this->client->user_id); - $payment->client_id = $this->client->id; - $payment->company_gateway_id = $this->company_gateway->id; - $payment->status_id = Payment::STATUS_COMPLETED; - $payment->gateway_type_id = $data['gateway_type_id']; - $payment->type_id = $data['type_id']; - $payment->currency_id = $this->client->getSetting('currency_id'); - $payment->date = Carbon::now(); - $payment->transaction_reference = $data['transaction_reference']; - $payment->amount = $amount; - $payment->save(); - - return $payment->service()->applyNumber()->save(); - } - /** * Attach Stripe payment method to Stripe client. * diff --git a/app/Utils/HtmlEngine.php b/app/Utils/HtmlEngine.php index 9373325d46b4..fdf8e0eeaa04 100644 --- a/app/Utils/HtmlEngine.php +++ b/app/Utils/HtmlEngine.php @@ -276,7 +276,7 @@ class HtmlEngine $data['$company.website'] = ['value' => $this->settings->website ?: ' ', 'label' => ctrans('texts.website')]; $data['$company.address'] = ['value' => $this->company->present()->address($this->settings) ?: ' ', 'label' => ctrans('texts.address')]; - $data['$spc_qr_code'] = ['value' => $this->company->present()->getSpcQrCode($this->client->custom1, $this->entity->number, $this->entity->balance), 'label' => '']; + $data['$spc_qr_code'] = ['value' => $this->company->present()->getSpcQrCode($this->client->currency()->code, $this->entity->number, $this->entity->balance), 'label' => '']; $logo = $this->company->present()->logo($this->settings); diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 95409d86f8a3..79dc87e19fd3 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -3382,4 +3382,6 @@ return [ 'user_detached' => 'User detached from company', 'create_webhook_failure' => 'Failed to create Webhook', 'number' => 'Number', + 'payment_message_extended' => 'Thank you for your payment of :amount for :invoice', + ];