mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Merge pull request #9891 from turbo124/v5-develop
Add log time to task exports
This commit is contained in:
commit
5fbf1eea1e
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -8,7 +8,7 @@ assignees: ''
|
|||||||
---
|
---
|
||||||
|
|
||||||
<!-- Before posting please check our "Troubleshooting" category in the docs:
|
<!-- Before posting please check our "Troubleshooting" category in the docs:
|
||||||
https://invoiceninja.github.io/docs/self-host-troubleshooting/ -->
|
https://invoiceninja.github.io/en/self-host-troubleshooting/ -->
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
- Version: <!-- i.e. v4.5.25 / v5.0.30 -->
|
- Version: <!-- i.e. v4.5.25 / v5.0.30 -->
|
||||||
|
@ -451,6 +451,7 @@ class BaseExport
|
|||||||
'project' => 'task.project_id',
|
'project' => 'task.project_id',
|
||||||
'billable' => 'task.billable',
|
'billable' => 'task.billable',
|
||||||
'item_notes' => 'task.item_notes',
|
'item_notes' => 'task.item_notes',
|
||||||
|
'time_log' => 'task.time_log',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected array $forced_client_fields = [
|
protected array $forced_client_fields = [
|
||||||
|
@ -156,7 +156,7 @@ class TaskExport extends BaseExport
|
|||||||
$entity[$key] = $transformed_entity[$parts[1]];
|
$entity[$key] = $transformed_entity[$parts[1]];
|
||||||
} elseif (array_key_exists($key, $transformed_entity)) {
|
} elseif (array_key_exists($key, $transformed_entity)) {
|
||||||
$entity[$key] = $transformed_entity[$key];
|
$entity[$key] = $transformed_entity[$key];
|
||||||
} elseif (in_array($key, ['task.start_date', 'task.end_date', 'task.duration', 'task.billable', 'task.item_notes'])) {
|
} elseif (in_array($key, ['task.start_date', 'task.end_date', 'task.duration', 'task.billable', 'task.item_notes', 'task.time_log'])) {
|
||||||
$entity[$key] = '';
|
$entity[$key] = '';
|
||||||
} else {
|
} else {
|
||||||
$entity[$key] = $this->decorator->transform($key, $task);
|
$entity[$key] = $this->decorator->transform($key, $task);
|
||||||
@ -207,6 +207,9 @@ class TaskExport extends BaseExport
|
|||||||
$seconds = $task->calcDuration();
|
$seconds = $task->calcDuration();
|
||||||
$entity['task.duration'] = $seconds;
|
$entity['task.duration'] = $seconds;
|
||||||
$entity['task.duration_words'] = $seconds > 86400 ? CarbonInterval::seconds($seconds)->locale($this->company->locale())->cascade()->forHumans() : now()->startOfDay()->addSeconds($seconds)->format('H:i:s');
|
$entity['task.duration_words'] = $seconds > 86400 ? CarbonInterval::seconds($seconds)->locale($this->company->locale())->cascade()->forHumans() : now()->startOfDay()->addSeconds($seconds)->format('H:i:s');
|
||||||
|
|
||||||
|
$entity['task.time_log'] = (isset($item[1]) && $item[1] != 0) ? $item[1] - $item[0] : ctrans('texts.is_running');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_array('task.billable', $this->input['report_keys']) || in_array('billable', $this->input['report_keys'])) {
|
if (in_array('task.billable', $this->input['report_keys']) || in_array('billable', $this->input['report_keys'])) {
|
||||||
|
@ -133,7 +133,7 @@ class UpdateTaskRequest extends Request
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!isset($input['time_log']) || empty($input['time_log']) || $input['time_log'] == '{}') {
|
if(!isset($input['time_log']) || empty($input['time_log']) || $input['time_log'] == '{}' || $input['time_log'] == '[""]') {
|
||||||
$input['time_log'] = json_encode([]);
|
$input['time_log'] = json_encode([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,7 +254,7 @@ class NinjaMailerJob implements ShouldQueue
|
|||||||
|
|
||||||
private function incrementEmailCounter(): void
|
private function incrementEmailCounter(): void
|
||||||
{
|
{
|
||||||
if(in_array($this->mailer, ['default','mailgun','postmark'])) {
|
if(in_array($this->nmo->settings->email_sending_method, ['default','mailgun','postmark'])) {
|
||||||
Cache::increment("email_quota".$this->company->account->key);
|
Cache::increment("email_quota".$this->company->account->key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ class AdjustEmailQuota implements ShouldQueue
|
|||||||
|
|
||||||
/** Use redis pipelines to execute bulk deletes efficiently */
|
/** Use redis pipelines to execute bulk deletes efficiently */
|
||||||
$redis = Redis::connection('sentinel-cache');
|
$redis = Redis::connection('sentinel-cache');
|
||||||
$prefix = config('cache.prefix'). ":email_quota*";
|
$prefix = config('cache.prefix'). "email_quota*";
|
||||||
|
|
||||||
$keys = $redis->keys($prefix);
|
$keys = $redis->keys($prefix);
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ class AdjustEmailQuota implements ShouldQueue
|
|||||||
}
|
}
|
||||||
$keys = null;
|
$keys = null;
|
||||||
|
|
||||||
$prefix = config('cache.prefix'). ":throttle_notified*";
|
$prefix = config('cache.prefix'). "throttle_notified*";
|
||||||
|
|
||||||
$keys = $redis->keys($prefix);
|
$keys = $redis->keys($prefix);
|
||||||
|
|
||||||
|
@ -58,10 +58,6 @@ class EmailPayment implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
if ($this->company->is_disabled || (!$this->contact?->email ?? false)) {
|
|
||||||
nlog("company disabled - or - contact email not found");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MultiDB::setDb($this->company->db);
|
MultiDB::setDb($this->company->db);
|
||||||
|
|
||||||
@ -71,6 +67,11 @@ class EmailPayment implements ShouldQueue
|
|||||||
$this->contact = $this->payment->client->contacts()->orderBy('is_primary', 'desc')->first();
|
$this->contact = $this->payment->client->contacts()->orderBy('is_primary', 'desc')->first();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->company->is_disabled || (!$this->contact?->email ?? false)) {
|
||||||
|
nlog("company disabled - or - contact email not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$this->contact->load('client');
|
$this->contact->load('client');
|
||||||
|
|
||||||
$email_builder = (new PaymentEmailEngine($this->payment, $this->contact))->build();
|
$email_builder = (new PaymentEmailEngine($this->payment, $this->contact))->build();
|
||||||
|
@ -262,6 +262,7 @@ class PaymentEmailEngine extends BaseEmailEngine
|
|||||||
$data['$client.email'] = &$data['$email'];
|
$data['$client.email'] = &$data['$email'];
|
||||||
|
|
||||||
$data['$client.balance'] = ['value' => Number::formatMoney($this->client->balance, $this->client), 'label' => ctrans('texts.account_balance')];
|
$data['$client.balance'] = ['value' => Number::formatMoney($this->client->balance, $this->client), 'label' => ctrans('texts.account_balance')];
|
||||||
|
$data['$client.payment_balance'] = ['value' => Number::formatMoney($this->client->payment_balance, $this->client), 'label' => ctrans('texts.payment_balance_on_file')];
|
||||||
$data['$outstanding'] = ['value' => Number::formatMoney($this->client->balance, $this->client), 'label' => ctrans('texts.account_balance')];
|
$data['$outstanding'] = ['value' => Number::formatMoney($this->client->balance, $this->client), 'label' => ctrans('texts.account_balance')];
|
||||||
$data['$client_balance'] = ['value' => Number::formatMoney($this->client->balance, $this->client), 'label' => ctrans('texts.account_balance')];
|
$data['$client_balance'] = ['value' => Number::formatMoney($this->client->balance, $this->client), 'label' => ctrans('texts.account_balance')];
|
||||||
$data['$paid_to_date'] = ['value' => Number::formatMoney($this->client->paid_to_date, $this->client), 'label' => ctrans('texts.paid_to_date')];
|
$data['$paid_to_date'] = ['value' => Number::formatMoney($this->client->paid_to_date, $this->client), 'label' => ctrans('texts.paid_to_date')];
|
||||||
|
@ -614,17 +614,17 @@ class Invoice extends BaseModel
|
|||||||
event(new InvoiceWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), $template));
|
event(new InvoiceWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), $template));
|
||||||
break;
|
break;
|
||||||
case 'reminder1':
|
case 'reminder1':
|
||||||
event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), $template));
|
event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), $reminder_template));
|
||||||
break;
|
break;
|
||||||
case 'reminder2':
|
case 'reminder2':
|
||||||
event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), $template));
|
event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), $reminder_template));
|
||||||
break;
|
break;
|
||||||
case 'reminder3':
|
case 'reminder3':
|
||||||
event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), $template));
|
event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), $reminder_template));
|
||||||
break;
|
break;
|
||||||
case 'reminder_endless':
|
case 'reminder_endless':
|
||||||
case 'endless_reminder':
|
case 'endless_reminder':
|
||||||
event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), $template));
|
event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), $reminder_template));
|
||||||
break;
|
break;
|
||||||
case 'custom1':
|
case 'custom1':
|
||||||
case 'custom2':
|
case 'custom2':
|
||||||
|
@ -400,6 +400,7 @@ class BaseDriver extends AbstractPaymentDriver
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
$invoices = Invoice::query()
|
$invoices = Invoice::query()
|
||||||
|
->where('company_id', $this->company_gateway->company_id)
|
||||||
->whereIn('id', $this->transformKeys(array_column($payment_invoices, 'invoice_id')))
|
->whereIn('id', $this->transformKeys(array_column($payment_invoices, 'invoice_id')))
|
||||||
->whereJsonContains('line_items', ['type_id' => '3'])
|
->whereJsonContains('line_items', ['type_id' => '3'])
|
||||||
->withTrashed();
|
->withTrashed();
|
||||||
@ -407,6 +408,7 @@ class BaseDriver extends AbstractPaymentDriver
|
|||||||
if($invoices->count() == 0){
|
if($invoices->count() == 0){
|
||||||
|
|
||||||
$invoice = Invoice::query()
|
$invoice = Invoice::query()
|
||||||
|
->where('company_id', $this->company_gateway->company_id)
|
||||||
->whereIn('id', $this->transformKeys(array_column($payment_invoices, 'invoice_id')))
|
->whereIn('id', $this->transformKeys(array_column($payment_invoices, 'invoice_id')))
|
||||||
->orderBy('id','desc')
|
->orderBy('id','desc')
|
||||||
->withTrashed()
|
->withTrashed()
|
||||||
|
@ -100,7 +100,16 @@ class PaymentMethod implements MethodInterface
|
|||||||
|
|
||||||
$customer = array_merge(['address' => $request->only('address_1','address_2','city','postal_code','province_code','country'), 'custom_identifier' => $request->input('custom_identifier') ], $request->all());
|
$customer = array_merge(['address' => $request->only('address_1','address_2','city','postal_code','province_code','country'), 'custom_identifier' => $request->input('custom_identifier') ], $request->all());
|
||||||
|
|
||||||
$this->rotessa->findOrCreateCustomer($customer);
|
try{
|
||||||
|
$this->rotessa->findOrCreateCustomer($customer);
|
||||||
|
}
|
||||||
|
catch(\Exception $e){
|
||||||
|
|
||||||
|
$message = json_decode($e->getMessage(), true);
|
||||||
|
|
||||||
|
return redirect()->route('client.payment_methods.index')->withErrors(array_values($message['errors']));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
return redirect()->route('client.payment_methods.index')->withMessage(ctrans('texts.payment_method_added'));
|
return redirect()->route('client.payment_methods.index')->withMessage(ctrans('texts.payment_method_added'));
|
||||||
|
|
||||||
|
@ -202,7 +202,6 @@ class RotessaPaymentDriver extends BaseDriver
|
|||||||
|
|
||||||
public function findOrCreateCustomer(array $data)
|
public function findOrCreateCustomer(array $data)
|
||||||
{
|
{
|
||||||
nlog($data);
|
|
||||||
|
|
||||||
$result = null;
|
$result = null;
|
||||||
try {
|
try {
|
||||||
@ -219,7 +218,6 @@ class RotessaPaymentDriver extends BaseDriver
|
|||||||
|
|
||||||
if(!isset($data['id'])) {
|
if(!isset($data['id'])) {
|
||||||
|
|
||||||
nlog("no id, lets goo");
|
|
||||||
$result = $this->gatewayRequest('post', 'customers', $data);
|
$result = $this->gatewayRequest('post', 'customers', $data);
|
||||||
|
|
||||||
if($result->failed())
|
if($result->failed())
|
||||||
@ -252,9 +250,16 @@ class RotessaPaymentDriver extends BaseDriver
|
|||||||
'code' => 500
|
'code' => 500
|
||||||
];
|
];
|
||||||
|
|
||||||
SystemLogger::dispatch(['server_response' => is_null($result) ? '' : $result->getMessage(), 'data' => $data], SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, 880 , $this->client, $this->company_gateway->company);
|
SystemLogger::dispatch(['server_response' => $data, 'data' => []], SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, 880 , $this->client, $this->company_gateway->company);
|
||||||
|
|
||||||
throw $th;
|
try{
|
||||||
|
$errors = explode("422:", $th->getMessage())[1];
|
||||||
|
}
|
||||||
|
catch(\Exception){
|
||||||
|
$errors = 'Unknown error occured';
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \Exception($errors, $th->getCode());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,24 +137,29 @@ class Storecove {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function sendDocument(string $document, int $routing_id, array $identifiers = [])
|
public function sendDocument(string $document, int $routing_id, array $override_payload = [])
|
||||||
{
|
{
|
||||||
|
|
||||||
$payload = [
|
$payload = [
|
||||||
"legalEntityId" => $routing_id,
|
"legalEntityId" => $routing_id,
|
||||||
"idempotencyGuid"=> \Illuminate\Support\Str::uuid(),
|
"idempotencyGuid"=> \Illuminate\Support\Str::uuid(),
|
||||||
"routing" => [
|
"routing" => [
|
||||||
"eIdentifiers" => $identifiers,
|
"eIdentifiers" => [],
|
||||||
"emails" => ["david@invoiceninja.com"]
|
"emails" => ["david@invoiceninja.com"]
|
||||||
],
|
],
|
||||||
"document"=> [
|
"document"=> [
|
||||||
'documentType' => 'invoice',
|
|
||||||
"rawDocumentData"=> [
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
$payload = array_merge($payload, $override_payload);
|
||||||
|
|
||||||
|
|
||||||
|
$payload['document']['documentType'] = 'invoice';
|
||||||
|
$payload['document']["rawDocumentData"] = [
|
||||||
"document" => base64_encode($document),
|
"document" => base64_encode($document),
|
||||||
"parse" => true,
|
"parse" => true,
|
||||||
"parseStrategy"=> "ubl",
|
"parseStrategy"=> "ubl",
|
||||||
],
|
|
||||||
],
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$uri = "document_submissions";
|
$uri = "document_submissions";
|
||||||
|
@ -13,22 +13,25 @@ namespace App\Services\EDocument\Standards;
|
|||||||
|
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
|
use App\Helpers\Invoice\Taxer;
|
||||||
use App\Services\AbstractService;
|
use App\Services\AbstractService;
|
||||||
use App\Helpers\Invoice\InvoiceSum;
|
use App\Helpers\Invoice\InvoiceSum;
|
||||||
use InvoiceNinja\EInvoice\EInvoice;
|
use InvoiceNinja\EInvoice\EInvoice;
|
||||||
|
use App\Utils\Traits\NumberFormatter;
|
||||||
use App\Helpers\Invoice\InvoiceSumInclusive;
|
use App\Helpers\Invoice\InvoiceSumInclusive;
|
||||||
use App\Helpers\Invoice\Taxer;
|
|
||||||
use InvoiceNinja\EInvoice\Models\Peppol\PaymentMeans;
|
use InvoiceNinja\EInvoice\Models\Peppol\PaymentMeans;
|
||||||
use InvoiceNinja\EInvoice\Models\Peppol\ItemType\Item;
|
use InvoiceNinja\EInvoice\Models\Peppol\ItemType\Item;
|
||||||
use InvoiceNinja\EInvoice\Models\Peppol\PartyType\Party;
|
use InvoiceNinja\EInvoice\Models\Peppol\PartyType\Party;
|
||||||
use InvoiceNinja\EInvoice\Models\Peppol\PriceType\Price;
|
use InvoiceNinja\EInvoice\Models\Peppol\PriceType\Price;
|
||||||
|
use InvoiceNinja\EInvoice\Models\Peppol\IdentifierType\ID;
|
||||||
use InvoiceNinja\EInvoice\Models\Peppol\AddressType\Address;
|
use InvoiceNinja\EInvoice\Models\Peppol\AddressType\Address;
|
||||||
use InvoiceNinja\EInvoice\Models\Peppol\ContactType\Contact;
|
use InvoiceNinja\EInvoice\Models\Peppol\ContactType\Contact;
|
||||||
use InvoiceNinja\EInvoice\Models\Peppol\CountryType\Country;
|
use InvoiceNinja\EInvoice\Models\Peppol\CountryType\Country;
|
||||||
|
use InvoiceNinja\EInvoice\Models\Peppol\PartyIdentification;
|
||||||
use InvoiceNinja\EInvoice\Models\Peppol\AmountType\TaxAmount;
|
use InvoiceNinja\EInvoice\Models\Peppol\AmountType\TaxAmount;
|
||||||
|
use InvoiceNinja\EInvoice\Models\Peppol\Party as PeppolParty;
|
||||||
use InvoiceNinja\EInvoice\Models\Peppol\TaxTotalType\TaxTotal;
|
use InvoiceNinja\EInvoice\Models\Peppol\TaxTotalType\TaxTotal;
|
||||||
use App\Services\EDocument\Standards\Settings\PropertyResolver;
|
use App\Services\EDocument\Standards\Settings\PropertyResolver;
|
||||||
use App\Utils\Traits\NumberFormatter;
|
|
||||||
use InvoiceNinja\EInvoice\Models\Peppol\AmountType\PriceAmount;
|
use InvoiceNinja\EInvoice\Models\Peppol\AmountType\PriceAmount;
|
||||||
use InvoiceNinja\EInvoice\Models\Peppol\PartyNameType\PartyName;
|
use InvoiceNinja\EInvoice\Models\Peppol\PartyNameType\PartyName;
|
||||||
use InvoiceNinja\EInvoice\Models\Peppol\TaxSchemeType\TaxScheme;
|
use InvoiceNinja\EInvoice\Models\Peppol\TaxSchemeType\TaxScheme;
|
||||||
@ -42,14 +45,13 @@ use InvoiceNinja\EInvoice\Models\Peppol\TaxScheme as PeppolTaxScheme;
|
|||||||
use InvoiceNinja\EInvoice\Models\Peppol\AmountType\TaxExclusiveAmount;
|
use InvoiceNinja\EInvoice\Models\Peppol\AmountType\TaxExclusiveAmount;
|
||||||
use InvoiceNinja\EInvoice\Models\Peppol\AmountType\TaxInclusiveAmount;
|
use InvoiceNinja\EInvoice\Models\Peppol\AmountType\TaxInclusiveAmount;
|
||||||
use InvoiceNinja\EInvoice\Models\Peppol\AmountType\LineExtensionAmount;
|
use InvoiceNinja\EInvoice\Models\Peppol\AmountType\LineExtensionAmount;
|
||||||
|
use InvoiceNinja\EInvoice\Models\Peppol\OrderReferenceType\OrderReference;
|
||||||
use InvoiceNinja\EInvoice\Models\Peppol\MonetaryTotalType\LegalMonetaryTotal;
|
use InvoiceNinja\EInvoice\Models\Peppol\MonetaryTotalType\LegalMonetaryTotal;
|
||||||
use InvoiceNinja\EInvoice\Models\Peppol\TaxCategoryType\ClassifiedTaxCategory;
|
use InvoiceNinja\EInvoice\Models\Peppol\TaxCategoryType\ClassifiedTaxCategory;
|
||||||
use InvoiceNinja\EInvoice\Models\Peppol\CustomerPartyType\AccountingCustomerParty;
|
use InvoiceNinja\EInvoice\Models\Peppol\CustomerPartyType\AccountingCustomerParty;
|
||||||
use InvoiceNinja\EInvoice\Models\Peppol\SupplierPartyType\AccountingSupplierParty;
|
use InvoiceNinja\EInvoice\Models\Peppol\SupplierPartyType\AccountingSupplierParty;
|
||||||
use InvoiceNinja\EInvoice\Models\Peppol\FinancialAccountType\PayeeFinancialAccount;
|
use InvoiceNinja\EInvoice\Models\Peppol\FinancialAccountType\PayeeFinancialAccount;
|
||||||
use InvoiceNinja\EInvoice\Models\Peppol\IdentifierType\ID;
|
use InvoiceNinja\EInvoice\Models\Peppol\IdentifierType\CustomerAssignedAccountID;
|
||||||
use InvoiceNinja\EInvoice\Models\Peppol\Party as PeppolParty;
|
|
||||||
use InvoiceNinja\EInvoice\Models\Peppol\PartyIdentification;
|
|
||||||
|
|
||||||
class Peppol extends AbstractService
|
class Peppol extends AbstractService
|
||||||
{
|
{
|
||||||
@ -103,7 +105,7 @@ class Peppol extends AbstractService
|
|||||||
'DE' => 'VAT', //tested - requires Payment Means to be defined.
|
'DE' => 'VAT', //tested - requires Payment Means to be defined.
|
||||||
'DK' => 'ERST',
|
'DK' => 'ERST',
|
||||||
'EE' => 'VAT',
|
'EE' => 'VAT',
|
||||||
'ES' => 'VAT',
|
'ES' => 'VAT', //tested - B2G pending
|
||||||
'FI' => 'VAT',
|
'FI' => 'VAT',
|
||||||
'FR' => 'VAT',
|
'FR' => 'VAT',
|
||||||
'GR' => 'VAT',
|
'GR' => 'VAT',
|
||||||
@ -165,6 +167,8 @@ class Peppol extends AbstractService
|
|||||||
|
|
||||||
private EInvoice $e;
|
private EInvoice $e;
|
||||||
|
|
||||||
|
private array $storecove_meta = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Invoice $invoice
|
* @param Invoice $invoice
|
||||||
*/
|
*/
|
||||||
@ -741,6 +745,14 @@ class Peppol extends AbstractService
|
|||||||
return $total;
|
return $total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////// Helper Methods /////////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* setInvoiceDefaults
|
||||||
|
*
|
||||||
|
* Stubs a default einvoice
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
public function setInvoiceDefaults(): self
|
public function setInvoiceDefaults(): self
|
||||||
{
|
{
|
||||||
$settings = [
|
$settings = [
|
||||||
@ -770,6 +782,14 @@ class Peppol extends AbstractService
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getSetting
|
||||||
|
*
|
||||||
|
* Attempts to harvest and return a preconfigured prop from company / client / invoice settings
|
||||||
|
*
|
||||||
|
* @param string $property_path
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
public function getSetting(string $property_path): mixed
|
public function getSetting(string $property_path): mixed
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -784,7 +804,13 @@ class Peppol extends AbstractService
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function countryLevelMutators():self
|
/**
|
||||||
|
* countryLevelMutators
|
||||||
|
*
|
||||||
|
* Runs country level specific requirements for the e-invoice
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
private function countryLevelMutators():self
|
||||||
{
|
{
|
||||||
|
|
||||||
if(method_exists($this, $this->invoice->company->country()->iso_3166_2))
|
if(method_exists($this, $this->invoice->company->country()->iso_3166_2))
|
||||||
@ -793,6 +819,13 @@ class Peppol extends AbstractService
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* setPaymentMeans
|
||||||
|
*
|
||||||
|
* Sets the payment means - if it exists
|
||||||
|
* @param bool $required
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
private function setPaymentMeans(bool $required = false): self
|
private function setPaymentMeans(bool $required = false): self
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -803,12 +836,152 @@ class Peppol extends AbstractService
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($required)
|
return $this->checkRequired($required, "Payment Means");
|
||||||
throw new \Exception('e-invoice generation halted:: Payment Means required');
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* setOrderReference
|
||||||
|
*
|
||||||
|
* sets the order reference - if it exists (Never rely on settings for this)
|
||||||
|
*
|
||||||
|
* @param bool $required
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
private function setOrderReference(bool $required = false): self
|
||||||
|
{
|
||||||
|
$this->p_invoice->BuyerReference = $this->invoice->po_number ?? '';
|
||||||
|
|
||||||
|
if(strlen($this->invoice->po_number ?? '') > 1)
|
||||||
|
{
|
||||||
|
$order_reference = new OrderReference();
|
||||||
|
$id = new ID();
|
||||||
|
$id->value = $this->invoice->po_number;
|
||||||
|
|
||||||
|
$order_reference->ID = $id;
|
||||||
|
|
||||||
|
$this->p_invoice->OrderReference = $order_reference;
|
||||||
|
|
||||||
|
// $this->setStorecoveMeta(["document" => [
|
||||||
|
// "invoice" => [
|
||||||
|
// [
|
||||||
|
// "references" => [
|
||||||
|
// "documentType" => "purchase_order",
|
||||||
|
// "documentId" => $this->invoice->po_number,
|
||||||
|
// ],
|
||||||
|
// ],
|
||||||
|
// ],
|
||||||
|
// ]
|
||||||
|
// ]);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->checkRequired($required, 'Order Reference');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* setCustomerAssignedAccountId
|
||||||
|
*
|
||||||
|
* Sets the client id_number CAN rely on settings
|
||||||
|
*
|
||||||
|
* @param bool $required
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
private function setCustomerAssignedAccountId(bool $required = false): self
|
||||||
|
{
|
||||||
|
//@phpstan-ignore-next-line
|
||||||
|
if(isset($this->p_invoice->AccountingCustomerParty->CustomerAssignedAccountID)){
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
elseif($customer_assigned_account_id = $this->getSetting('Invoice.AccountingCustomerParty.CustomerAssignedAccountID')){
|
||||||
|
|
||||||
|
$this->p_invoice->AccountingCustomerParty->CustomerAssignedAccountID = $customer_assigned_account_id;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
elseif(strlen($this->invoice->client->id_number ?? '') > 1){
|
||||||
|
|
||||||
|
$customer_assigned_account_id = new CustomerAssignedAccountID();
|
||||||
|
$customer_assigned_account_id->value = $this->invoice->client->id_number;
|
||||||
|
|
||||||
|
$this->p_invoice->AccountingCustomerParty->CustomerAssignedAccountID = $customer_assigned_account_id;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//@phpstan-ignore-next-line
|
||||||
|
return $this->checkRequired($required, 'Client ID Number');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check Required
|
||||||
|
*
|
||||||
|
* Throws if a required field is missing.
|
||||||
|
*
|
||||||
|
* @param bool $required
|
||||||
|
* @param string $section
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
private function checkRequired(bool $required, string $section): self
|
||||||
|
{
|
||||||
|
|
||||||
|
return $required ? throw new \Exception("e-invoice generation halted:: {$section} required") : $this;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds the Routing object for StoreCove
|
||||||
|
*
|
||||||
|
* @param string $schemeId
|
||||||
|
* @param string $id
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function buildRouting(string $schemeId, string $id): array
|
||||||
|
{
|
||||||
|
|
||||||
|
return
|
||||||
|
[
|
||||||
|
"routing" => [
|
||||||
|
"publicIdentifiers" => [
|
||||||
|
[
|
||||||
|
"scheme" => $schemeId,
|
||||||
|
"id" => $id
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* setStorecoveMeta
|
||||||
|
*
|
||||||
|
* updates the storecove payload for sending documents
|
||||||
|
*
|
||||||
|
* @param array $meta
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
private function setStorecoveMeta(array $meta): self
|
||||||
|
{
|
||||||
|
$this->storecove_meta = array_merge($this->storecove_meta, $meta);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getStorecoveMeta(): array
|
||||||
|
{
|
||||||
|
return $this->storecove_meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////// Country level mutators /////////////////////////////////////
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DE
|
* DE
|
||||||
*
|
*
|
||||||
@ -867,10 +1040,10 @@ class Peppol extends AbstractService
|
|||||||
* ES
|
* ES
|
||||||
*
|
*
|
||||||
* @Pending
|
* @Pending
|
||||||
|
* B2G configuration
|
||||||
|
* B2G Testing
|
||||||
*
|
*
|
||||||
* ES:DIRE - routing identifier
|
* testing. // routing identifier - 293098
|
||||||
*
|
|
||||||
* testing. //293098
|
|
||||||
*
|
*
|
||||||
* @return self
|
* @return self
|
||||||
*/
|
*/
|
||||||
@ -921,19 +1094,44 @@ class Peppol extends AbstractService
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FR
|
||||||
|
* @Pending - clarification on codes needed
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
private function FR(): self
|
private function FR(): self
|
||||||
{
|
{
|
||||||
|
|
||||||
// When sending invoices to the French government (Chorus Pro):
|
// When sending invoices to the French government (Chorus Pro):
|
||||||
|
|
||||||
// All invoices have to be routed to SIRET 0009:11000201100044. There is no test environment for sending to public entities.
|
// All invoices have to be routed to SIRET 0009:11000201100044. There is no test environment for sending to public entities.
|
||||||
|
|
||||||
// The SIRET / 0009 identifier of the final recipient is to be included in the invoice.accountingCustomerParty.publicIdentifiers array.
|
// The SIRET / 0009 identifier of the final recipient is to be included in the invoice.accountingCustomerParty.publicIdentifiers array.
|
||||||
|
|
||||||
|
if($this->invoice->client->classification == 'government'){
|
||||||
|
//route to SIRET 0009:11000201100044
|
||||||
|
$this->setStorecoveMeta($this->buildRouting('FR:SIRET', "0009:11000201100044"));
|
||||||
|
|
||||||
|
// The SIRET / 0009 identifier of the final recipient is to be included in the invoice.accountingCustomerParty.publicIdentifiers array.
|
||||||
|
$this->setCustomerAssignedAccountId(true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strlen($this->invoice->client->id_number ?? '') == 9) {
|
||||||
|
//SIREN
|
||||||
|
$this->setStorecoveMeta($this->buildRouting('FR:SIREN', "0002:{$this->invoice->client->id_number}"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//SIRET
|
||||||
|
$this->setStorecoveMeta($this->buildRouting('FR:SIRET', "0009:{$this->invoice->client->id_number}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ??????????????????????? //@TODO
|
||||||
// The service code must be sent in invoice.buyerReference (deprecated) or the invoice.references array (documentType buyer_reference)
|
// The service code must be sent in invoice.buyerReference (deprecated) or the invoice.references array (documentType buyer_reference)
|
||||||
|
|
||||||
// The commitment number must be sent in the invoice.orderReference (deprecated) or the invoice.references array (documentType purchase_order).
|
if(strlen($this->invoice->po_number ?? '') >1) {
|
||||||
|
$this->setOrderReference(false);
|
||||||
|
}
|
||||||
|
|
||||||
// Invoices to companies (SIRET / 0009 or SIRENE / 0002) are routed directly to that identifier.
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,7 +250,7 @@ class Email implements ShouldQueue
|
|||||||
|
|
||||||
private function incrementEmailCounter(): void
|
private function incrementEmailCounter(): void
|
||||||
{
|
{
|
||||||
if(in_array($this->mailer, ['default','mailgun','postmark'])) {
|
if(in_array($this->email_object->settings->email_sending_method, ['default','mailgun','postmark'])) {
|
||||||
Cache::increment("email_quota".$this->company->account->key);
|
Cache::increment("email_quota".$this->company->account->key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
"asm/php-ansible": "dev-main",
|
"asm/php-ansible": "dev-main",
|
||||||
"authorizenet/authorizenet": "^2.0",
|
"authorizenet/authorizenet": "^2.0",
|
||||||
"awobaz/compoships": "^2.1",
|
"awobaz/compoships": "^2.1",
|
||||||
|
"aws/aws-sdk-php": "^3.319",
|
||||||
"bacon/bacon-qr-code": "^2.0",
|
"bacon/bacon-qr-code": "^2.0",
|
||||||
"beganovich/snappdf": "dev-master",
|
"beganovich/snappdf": "dev-master",
|
||||||
"braintree/braintree_php": "^6.0",
|
"braintree/braintree_php": "^6.0",
|
||||||
|
19
composer.lock
generated
19
composer.lock
generated
@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "6eda3a2962158b87dab46711e65a8438",
|
"content-hash": "95e7bd229644d1d8e768ecfbc78582cd",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "adrienrn/php-mimetyper",
|
"name": "adrienrn/php-mimetyper",
|
||||||
@ -535,16 +535,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "aws/aws-sdk-php",
|
"name": "aws/aws-sdk-php",
|
||||||
"version": "3.317.1",
|
"version": "3.319.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/aws/aws-sdk-php.git",
|
"url": "https://github.com/aws/aws-sdk-php.git",
|
||||||
"reference": "dc1e3031c2721a25beb2e8fbb175b576e3d60ab9"
|
"reference": "a5c408d4cd1945d5fc817f45e46383634b610497"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/dc1e3031c2721a25beb2e8fbb175b576e3d60ab9",
|
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/a5c408d4cd1945d5fc817f45e46383634b610497",
|
||||||
"reference": "dc1e3031c2721a25beb2e8fbb175b576e3d60ab9",
|
"reference": "a5c408d4cd1945d5fc817f45e46383634b610497",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -597,7 +597,10 @@
|
|||||||
],
|
],
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"Aws\\": "src/"
|
"Aws\\": "src/"
|
||||||
}
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"src/data/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": [
|
"license": [
|
||||||
@ -624,9 +627,9 @@
|
|||||||
"support": {
|
"support": {
|
||||||
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
|
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
|
||||||
"issues": "https://github.com/aws/aws-sdk-php/issues",
|
"issues": "https://github.com/aws/aws-sdk-php/issues",
|
||||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.317.1"
|
"source": "https://github.com/aws/aws-sdk-php/tree/3.319.0"
|
||||||
},
|
},
|
||||||
"time": "2024-08-02T18:09:42+00:00"
|
"time": "2024-08-07T18:05:51+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "bacon/bacon-qr-code",
|
"name": "bacon/bacon-qr-code",
|
||||||
|
@ -5313,7 +5313,7 @@ $lang = array(
|
|||||||
'forever_free' => 'Forever Free',
|
'forever_free' => 'Forever Free',
|
||||||
'comments_only' => 'Comments Only',
|
'comments_only' => 'Comments Only',
|
||||||
'payment_balance_on_file' => 'Payment Balance On File',
|
'payment_balance_on_file' => 'Payment Balance On File',
|
||||||
|
'ubl_email_attachment_help' => 'For more e-invoice settings please navigate :here',
|
||||||
);
|
);
|
||||||
|
|
||||||
return $lang;
|
return $lang;
|
||||||
|
@ -2,6 +2,13 @@
|
|||||||
@section('meta_title', ctrans('texts.dashboard'))
|
@section('meta_title', ctrans('texts.dashboard'))
|
||||||
|
|
||||||
@section('body')
|
@section('body')
|
||||||
|
|
||||||
|
@if($client->getSetting('custom_message_dashboard'))
|
||||||
|
@component('portal.ninja2020.components.message')
|
||||||
|
<pre>{{ $client->getSetting('custom_message_dashboard') }}</pre>
|
||||||
|
@endcomponent
|
||||||
|
@endif
|
||||||
|
|
||||||
<div class="flex flex-col xl:flex-row gap-4">
|
<div class="flex flex-col xl:flex-row gap-4">
|
||||||
<div class="w-full rounded-md border border-[#E5E7EB] bg-white p-5 text-sm text-[#6C727F]">
|
<div class="w-full rounded-md border border-[#E5E7EB] bg-white p-5 text-sm text-[#6C727F]">
|
||||||
<h3 class="mb-4 text-xl font-semibold text-[#212529]">{{ $contact->first_name }} {{ $contact->last_name }}</h3>
|
<h3 class="mb-4 text-xl font-semibold text-[#212529]">{{ $contact->first_name }} {{ $contact->last_name }}</h3>
|
||||||
|
@ -2,6 +2,17 @@
|
|||||||
@section('meta_title', ctrans('texts.payment_methods'))
|
@section('meta_title', ctrans('texts.payment_methods'))
|
||||||
|
|
||||||
@section('body')
|
@section('body')
|
||||||
|
|
||||||
|
@section('header')
|
||||||
|
@if($errors->any())
|
||||||
|
<div class="alert alert-failure mb-4">
|
||||||
|
@foreach($errors->all() as $error)
|
||||||
|
<p>{{ $error }}</p>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
@endsection
|
||||||
|
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
@livewire('payment-methods-table', ['client_id' => $client->id, 'db' => $company->db])
|
@livewire('payment-methods-table', ['client_id' => $client->id, 'db' => $company->db])
|
||||||
</div>
|
</div>
|
||||||
|
@ -224,6 +224,25 @@ class TaskApiTest extends TestCase
|
|||||||
])->postJson("/api/v1/tasks", $data);
|
])->postJson("/api/v1/tasks", $data);
|
||||||
|
|
||||||
$response->assertStatus(200);
|
$response->assertStatus(200);
|
||||||
|
$arr = $response->json();
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'client_id' => $this->client->hashed_id,
|
||||||
|
'description' => 'Test Task',
|
||||||
|
'time_log' => '[""]',
|
||||||
|
'assigned_user' => [],
|
||||||
|
'project' => [],
|
||||||
|
'user' => [],
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->putJson("/api/v1/tasks/".$arr['data']['id'], $data);
|
||||||
|
|
||||||
|
$response->assertStatus(200);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
public function testUserFilters()
|
public function testUserFilters()
|
||||||
|
@ -505,6 +505,117 @@ $x = '<?xml version="1.0" encoding="utf-8"?>
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function createFRData()
|
||||||
|
{
|
||||||
|
$this->routing_id = 293338;
|
||||||
|
|
||||||
|
$settings = CompanySettings::defaults();
|
||||||
|
$settings->company_logo = 'https://pdf.invoicing.co/favicon-v2.png';
|
||||||
|
$settings->website = 'www.invoiceninja.de';
|
||||||
|
|
||||||
|
$settings->address1 = '10 Rue de la Paix';
|
||||||
|
$settings->address2 = 'Bâtiment A, Bureau 5';
|
||||||
|
$settings->city = 'Paris';
|
||||||
|
$settings->state = 'Île-de-France';
|
||||||
|
$settings->postal_code = '75002';
|
||||||
|
$settings->phone = '01 23456789';
|
||||||
|
$settings->email = $this->faker->unique()->safeEmail();
|
||||||
|
$settings->country_id = '250'; // France's ISO country code
|
||||||
|
$settings->vat_number = 'FR82345678911';
|
||||||
|
$settings->id_number = '12345678900010';
|
||||||
|
$settings->classification = 'business';
|
||||||
|
$settings->use_credits_payment = 'always';
|
||||||
|
$settings->timezone_id = '1'; // CET (Central European Time)
|
||||||
|
$settings->entity_send_time = 0;
|
||||||
|
$settings->e_invoice_type = 'PEPPOL';
|
||||||
|
$settings->currency_id = '3';
|
||||||
|
|
||||||
|
$company = Company::factory()->create([
|
||||||
|
'account_id' => $this->account->id,
|
||||||
|
'settings' => $settings,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->user->companies()->attach($company->id, [
|
||||||
|
'account_id' => $this->account->id,
|
||||||
|
'is_owner' => true,
|
||||||
|
'is_admin' => 1,
|
||||||
|
'is_locked' => 0,
|
||||||
|
'permissions' => '',
|
||||||
|
'notifications' => CompanySettings::notificationAdminDefaults(),
|
||||||
|
'settings' => null,
|
||||||
|
]);
|
||||||
|
|
||||||
|
Client::unguard();
|
||||||
|
|
||||||
|
$c =
|
||||||
|
Client::create([
|
||||||
|
'company_id' => $company->id,
|
||||||
|
'user_id' => $this->user->id,
|
||||||
|
'name' => 'Exemple Société S.A.',
|
||||||
|
'website' => 'https://www.exemple-societe.fr',
|
||||||
|
'private_notes' => 'Ceci est une note privée pour le client test.',
|
||||||
|
'balance' => 0,
|
||||||
|
'paid_to_date' => 0,
|
||||||
|
'vat_number' => 'FR12345678901',
|
||||||
|
'id_number' => '12345678900010', // Typical format for French company registration numbers
|
||||||
|
'custom_value1' => '2024-07-22 10:00:00',
|
||||||
|
'custom_value2' => 'bleu',
|
||||||
|
'custom_value3' => 'motexemple',
|
||||||
|
'custom_value4' => 'test@example.com',
|
||||||
|
'address1' => '123 Rue de l\'Exemple',
|
||||||
|
'address2' => '2ème étage, Bureau 45',
|
||||||
|
'city' => 'Paris',
|
||||||
|
'state' => 'Île-de-France',
|
||||||
|
'postal_code' => '75001',
|
||||||
|
'country_id' => '250', // France
|
||||||
|
'shipping_address1' => '123 Rue de l\'Exemple',
|
||||||
|
'shipping_address2' => '2ème étage, Bureau 45',
|
||||||
|
'shipping_city' => 'Paris',
|
||||||
|
'shipping_state' => 'Île-de-France',
|
||||||
|
'shipping_postal_code' => '75001',
|
||||||
|
'shipping_country_id' => '250', // France
|
||||||
|
'classification' => 'business',
|
||||||
|
'settings' => ClientSettings::Defaults(),
|
||||||
|
'client_hash' => \Illuminate\Support\Str::random(32),
|
||||||
|
'routing_id' => '',
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
$item = new InvoiceItem();
|
||||||
|
$item->product_key = "Product Key";
|
||||||
|
$item->notes = "Product Description";
|
||||||
|
$item->cost = 10;
|
||||||
|
$item->quantity = 10;
|
||||||
|
$item->tax_rate1 = 20;
|
||||||
|
$item->tax_name1 = 'VAT';
|
||||||
|
|
||||||
|
$invoice = Invoice::factory()->create([
|
||||||
|
'company_id' => $company->id,
|
||||||
|
'user_id' => $this->user->id,
|
||||||
|
'client_id' => $c->id,
|
||||||
|
'discount' => 0,
|
||||||
|
'uses_inclusive_taxes' => false,
|
||||||
|
'status_id' => 1,
|
||||||
|
'tax_rate1' => 0,
|
||||||
|
'tax_name1' => '',
|
||||||
|
'tax_rate2' => 0,
|
||||||
|
'tax_rate3' => 0,
|
||||||
|
'tax_name2' => '',
|
||||||
|
'tax_name3' => '',
|
||||||
|
'line_items' => [$item],
|
||||||
|
'number' => 'DE-'.rand(1000, 100000),
|
||||||
|
'date' => now()->format('Y-m-d'),
|
||||||
|
'due_date' => now()->addDays(14)->format('Y-m-d'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$invoice = $invoice->calc()->getInvoice();
|
||||||
|
$invoice->service()->markSent()->save();
|
||||||
|
|
||||||
|
|
||||||
|
return $invoice;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private function createDEData()
|
private function createDEData()
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -614,7 +725,39 @@ $x = '<?xml version="1.0" encoding="utf-8"?>
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testEsRules()
|
public function testFrRules()
|
||||||
|
{
|
||||||
|
|
||||||
|
$invoice = $this->createFRData();
|
||||||
|
|
||||||
|
$e_invoice = new \InvoiceNinja\EInvoice\Models\Peppol\Invoice();
|
||||||
|
|
||||||
|
$stub = json_decode('{"Invoice":{"Note":"Nooo","PaymentMeans":[{"ID":{"value":"afdasfasdfasdfas"},"PayeeFinancialAccount":{"Name":"PFA-NAME","ID":{"value":"DE89370400440532013000"},"AliasName":"PFA-Alias","AccountTypeCode":{"value":"CHECKING"},"AccountFormatCode":{"value":"IBAN"},"CurrencyCode":{"value":"EUR"},"FinancialInstitutionBranch":{"ID":{"value":"DEUTDEMMXXX"},"Name":"Deutsche Bank"}}}]}}');
|
||||||
|
foreach($stub as $key => $value) {
|
||||||
|
$e_invoice->{$key} = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
$invoice->e_invoice = $e_invoice;
|
||||||
|
$invoice->save();
|
||||||
|
|
||||||
|
$this->assertInstanceOf(Invoice::class, $invoice);
|
||||||
|
$this->assertInstanceof(\InvoiceNinja\EInvoice\Models\Peppol\Invoice::class, $e_invoice);
|
||||||
|
|
||||||
|
$p = new Peppol($invoice);
|
||||||
|
|
||||||
|
$p->run();
|
||||||
|
$xml = $p->toXml();
|
||||||
|
nlog($xml);
|
||||||
|
|
||||||
|
$identifiers = $p->getStorecoveMeta();
|
||||||
|
|
||||||
|
$sc = new \App\Services\EDocument\Gateway\Storecove\Storecove();
|
||||||
|
$sc->sendDocument($xml, $this->routing_id, $identifiers);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function RtestEsRules()
|
||||||
{
|
{
|
||||||
|
|
||||||
$invoice = $this->createESData();
|
$invoice = $this->createESData();
|
||||||
@ -639,10 +782,14 @@ $x = '<?xml version="1.0" encoding="utf-8"?>
|
|||||||
nlog($xml);
|
nlog($xml);
|
||||||
|
|
||||||
$identifiers = [
|
$identifiers = [
|
||||||
[
|
"routing" => [
|
||||||
'scheme' => 'ES:VAT',
|
"eIdentifiers" => [
|
||||||
'id' => 'ESB53625999'
|
[
|
||||||
],
|
'scheme' => 'ES:VAT',
|
||||||
|
'id' => 'ESB53625999'
|
||||||
|
],
|
||||||
|
]
|
||||||
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
$sc = new \App\Services\EDocument\Gateway\Storecove\Storecove();
|
$sc = new \App\Services\EDocument\Gateway\Storecove\Storecove();
|
||||||
@ -650,7 +797,7 @@ $x = '<?xml version="1.0" encoding="utf-8"?>
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testDeRules()
|
public function RtestDeRules()
|
||||||
{
|
{
|
||||||
$invoice = $this->createDEData();
|
$invoice = $this->createDEData();
|
||||||
|
|
||||||
@ -673,9 +820,13 @@ $x = '<?xml version="1.0" encoding="utf-8"?>
|
|||||||
nlog($xml);
|
nlog($xml);
|
||||||
|
|
||||||
$identifiers = [
|
$identifiers = [
|
||||||
[
|
"routing" => [
|
||||||
'scheme' => 'DE:VAT',
|
"eIdentifiers" => [
|
||||||
'id' => 'DE010101010'
|
[
|
||||||
|
'scheme' => 'DE:VAT',
|
||||||
|
'id' => 'DE010101010'
|
||||||
|
]
|
||||||
|
]
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user