Skip to content

Commit

Permalink
assets
Browse files Browse the repository at this point in the history
  • Loading branch information
turbo124 committed Oct 25, 2024
1 parent 8c7b31c commit a352d8d
Show file tree
Hide file tree
Showing 6 changed files with 557 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
<?php

namespace App\Services\EDocument\Gateway\Storecove;

use App\Services\EDocument\Gateway\Storecove\Models\Tax;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader;
use App\Services\EDocument\Gateway\Storecove\Models\InvoiceLines;
use InvoiceNinja\EInvoice\Models\Peppol\Invoice as PeppolInvoice;
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
use Symfony\Component\Serializer\NameConverter\MetadataAwareNameConverter;
use App\Services\EDocument\Gateway\Storecove\Models\Invoice as StorecoveInvoice;
use Symfony\Component\Serializer\SerializerInterface;


class PeppolToStorecoveNormalizer implements DenormalizerInterface
{
private SerializerInterface $serializer;
private ObjectNormalizer $objectNormalizer;


public function __construct(SerializerInterface $serializer)
{


$this->serializer = $serializer;

$classMetadataFactory = new ClassMetadataFactory(new AttributeLoader());
$metadataAwareNameConverter = new MetadataAwareNameConverter($classMetadataFactory);
$this->objectNormalizer = new ObjectNormalizer($classMetadataFactory, $metadataAwareNameConverter);

}

public function denormalize(mixed $data, string $type, string $format = null, array $context = []): mixed
{
$peppolInvoice = $data;
$storecoveInvoice = new StorecoveInvoice();


$storecoveInvoice->setDocumentCurrency($peppolInvoice->DocumentCurrencyCode ?? '');
$storecoveInvoice->setInvoiceNumber($peppolInvoice->ID ?? '');
$storecoveInvoice->setIssueDate($peppolInvoice->IssueDate);
$storecoveInvoice->setDueDate($peppolInvoice->DueDate);
$storecoveInvoice->setNote($peppolInvoice->Note ?? '');
$storecoveInvoice->setAmountIncludingVat((float)($peppolInvoice->LegalMonetaryTotal->TaxInclusiveAmount->amount ?? 0));

if (isset($peppolInvoice->InvoicePeriod[0])) {
$storecoveInvoice->setInvoicePeriod([
'startDate' => $peppolInvoice->InvoicePeriod[0]->StartDate,
'endDate' => $peppolInvoice->InvoicePeriod[0]->EndDate,
]);
}

$storecoveInvoice->setReferences([
'buyerReference' => $peppolInvoice->BuyerReference ?? '',
'orderReference' => $peppolInvoice->OrderReference->ID->value ?? '',
]);

if (isset($peppolInvoice->AccountingSupplierParty->Party)) {
$supplier = $peppolInvoice->AccountingSupplierParty->Party;
$storecoveInvoice->setAccountingSupplierParty([
'name' => $supplier->PartyName[0]->Name ?? '',
'vatNumber' => $supplier->PartyIdentification[0]->ID->value ?? '',
'streetName' => $supplier->PostalAddress->StreetName ?? '',
'cityName' => $supplier->PostalAddress->CityName ?? '',
'postalZone' => $supplier->PostalAddress->PostalZone ?? '',
'countryCode' => $supplier->PostalAddress->Country->IdentificationCode->value ?? '',
]);
}

if (isset($peppolInvoice->AccountingCustomerParty->Party)) {
$customer = $peppolInvoice->AccountingCustomerParty->Party;
$storecoveInvoice->setAccountingCustomerParty([
'name' => $customer->PartyName[0]->Name ?? '',
'vatNumber' => $customer->PartyIdentification[0]->ID->value ?? '',
'streetName' => $customer->PostalAddress->StreetName ?? '',
'cityName' => $customer->PostalAddress->CityName ?? '',
'postalZone' => $customer->PostalAddress->PostalZone ?? '',
'countryCode' => $customer->PostalAddress->Country->IdentificationCode->value ?? '',
]);
}

if (isset($peppolInvoice->PaymentMeans[0])) {
$storecoveInvoice->setPaymentMeans([
'paymentID' => $peppolInvoice->PaymentMeans[0]->PayeeFinancialAccount->ID->value ?? '',
]);
}

// Map tax total at invoice level
$taxTotal = [];
if (isset($peppolInvoice->InvoiceLine[0]->TaxTotal[0])) {
$taxTotal[] = [
'taxAmount' => (float)($peppolInvoice->InvoiceLine[0]->TaxTotal[0]->TaxAmount->amount ?? 0),
'taxCurrency' => $peppolInvoice->DocumentCurrencyCode ?? '',
];
}
$storecoveInvoice->setTaxTotal($taxTotal);

if (isset($peppolInvoice->InvoiceLine)) {
$invoiceLines = [];
foreach ($peppolInvoice->InvoiceLine as $line) {
$invoiceLine = new InvoiceLines();
$invoiceLine->setLineId($line->ID->value ?? '');
$invoiceLine->setAmountExcludingVat((float)($line->LineExtensionAmount->amount ?? 0));
$invoiceLine->setQuantity((float)($line->InvoicedQuantity ?? 0));
$invoiceLine->setQuantityUnitCode(''); // Not present in the provided JSON
$invoiceLine->setItemPrice((float)($line->Price->PriceAmount->amount ?? 0));
$invoiceLine->setName($line->Item->Name ?? '');
$invoiceLine->setDescription($line->Item->Description ?? '');

$tax = new Tax();
if (isset($line->TaxTotal[0])) {
$taxTotal = $line->TaxTotal[0];
$tax->setTaxAmount((float)($taxTotal->TaxAmount->amount ?? 0));

if (isset($line->Item->ClassifiedTaxCategory[0])) {
$taxCategory = $line->Item->ClassifiedTaxCategory[0];
$tax->setTaxPercentage((float)($taxCategory->Percent ?? 0));
$tax->setTaxCategory($taxCategory->ID->value ?? '');
}

$tax->setTaxableAmount((float)($line->LineExtensionAmount->amount ?? 0));
}
$invoiceLine->setTax($tax);

$invoiceLines[] = $invoiceLine;
}
$storecoveInvoice->setInvoiceLines($invoiceLines);
}

return $storecoveInvoice;


}

private function validateStorecoveInvoice(StorecoveInvoice $invoice): void
{
$requiredFields = ['documentCurrency', 'invoiceNumber', 'issueDate', 'dueDate'];
foreach ($requiredFields as $field) {
if (empty($invoice->$field)) {
throw new \InvalidArgumentException("Required field '$field' is missing or empty");
}
}

if (empty($invoice->invoiceLines)) {
throw new \InvalidArgumentException("Invoice must have at least one line item");
}

// Add more validations as needed
}

public function supportsDenormalization(mixed $data, string $type, string $format = null, array $context = []): bool
{
return $type === StorecoveInvoice::class && $data instanceof PeppolInvoice;
}

public function getSupportedTypes(?string $format): array
{
return [
StorecoveInvoice::class => true,
];
}

private function mapNestedProperties($object, array $nestedPaths): array
{
$result = [];
foreach ($nestedPaths as $key => $path) {
if (is_array($path)) {
// Try multiple paths
foreach ($path as $possiblePath) {
$value = $this->getValueFromPath($object, $possiblePath);
if ($value !== null) {
$result[$key] = $value;
nlog("Mapped nested property: $key", ['path' => $possiblePath, 'value' => $value]);
break;
}
}
if (!isset($result[$key])) {
nlog("Failed to map nested property: $key", ['paths' => $path]);
}
} else {
$value = $this->getValueFromPath($object, $path);
if ($value !== null) {
$result[$key] = $value;
nlog("Mapped nested property: $key", ['path' => $path, 'value' => $value]);
} else {
nlog("Failed to map nested property: $key", ['path' => $path]);
}
}
}
return $result;
}

private function getValueFromPath($object, string $path)
{
$parts = explode('.', $path);
$value = $object;
foreach ($parts as $part) {
if (preg_match('/(.+)\[(\d+)\]/', $part, $matches)) {
$property = $matches[1];
$index = $matches[2];
$value = $value->$property[$index] ?? null;
} else {
$value = $value->$part ?? null;
}
if ($value === null) {
nlog("Null value encountered in path: $path at part: $part");
return null;
}
}
return $value instanceof \DateTime ? $value->format('Y-m-d') : $value;
}

private function castValue(string $property, $value)
{
try {
$reflectionProperty = new \ReflectionProperty(StorecoveInvoice::class, $property);
$type = $reflectionProperty->getType();

if ($type instanceof \ReflectionNamedType) {
switch ($type->getName()) {
case 'float':
return (float) $value;
case 'int':
return (int) $value;
case 'string':
return (string) $value;
case 'bool':
return (bool) $value;
case 'array':
return (array) $value;
default:
return $value;
}
}
} catch (\ReflectionException $e) {
nlog("Error casting value for property: $property", ['error' => $e->getMessage()]);
}

return $value;
}
}
69 changes: 68 additions & 1 deletion lang/ar/texts.php
Original file line number Diff line number Diff line change
Expand Up @@ -2345,7 +2345,7 @@
'currency_gold_troy_ounce' => 'أونصة تروي ذهبية',
'currency_nicaraguan_córdoba' => 'قرطبة نيكاراغوا',
'currency_malagasy_ariary' => 'أرياري مدغشقر',
"currency_tongan_paanga" => "بانغا تونغا",
"currency_tongan_pa_anga" => "بانغا تونغا",

'review_app_help' => 'نأمل أن تستمتع باستخدام التطبيق.<br/> إذا كنت تفكر في :link فإننا نقدر ذلك كثيرًا!',
'writing_a_review' => 'كتابة مراجعة',
Expand Down Expand Up @@ -5319,6 +5319,73 @@
'no_unread_notifications' => 'لقد تم اللحاق بكل شيء! لا توجد إشعارات جديدة.',
'how_to_import_data' => 'كيفية استيراد البيانات',
'download_example_file' => 'تنزيل ملف المثال',
'expense_mailbox' => 'عنوان البريد الإلكتروني الوارد',
'expense_mailbox_help' => 'عنوان البريد الإلكتروني الوارد الذي يقبل مستندات النفقات. على سبيل المثال، [email protected]',
'expense_mailbox_active' => 'صندوق بريد النفقات',
'expense_mailbox_active_help' => 'يتيح معالجة المستندات مثل الإيصالات لإعداد تقارير النفقات',
'inbound_mailbox_allow_company_users' => 'السماح لمرسلي الشركة',
'inbound_mailbox_allow_company_users_help' => 'يسمح للمستخدمين داخل الشركة بإرسال مستندات النفقات.',
'inbound_mailbox_allow_vendors' => 'السماح لمرسلي البائعين',
'inbound_mailbox_allow_vendors_help' => 'يسمح لبائعي الشركة بإرسال مستندات النفقات',
'inbound_mailbox_allow_clients' => 'السماح لمرسلي العميل',
'inbound_mailbox_allow_clients_help' => 'يسمح للعملاء بإرسال مستندات النفقات',
'inbound_mailbox_whitelist' => 'قائمة السماح للمرسلين الواردين',
'inbound_mailbox_whitelist_help' => 'قائمة منفصلة بفواصل للرسائل الإلكترونية التي ينبغي السماح لها بإرسال رسائل إلكترونية للمعالجة',
'inbound_mailbox_blacklist' => 'قائمة المرسلين المحظورين',
'inbound_mailbox_blacklist_help' => 'قائمة منفصلة بفواصل للرسائل الإلكترونية التي لا يُسمح بإرسال رسائل إلكترونية إليها للمعالجة',
'inbound_mailbox_allow_unknown' => 'السماح لجميع المرسلين',
'inbound_mailbox_allow_unknown_help' => 'السماح لأي شخص بإرسال بريد إلكتروني للنفقات للمعالجة',
'quick_actions' => 'الإجراءات السريعة',
'end_all_sessions_help' => 'يقوم بتسجيل خروج جميع المستخدمين ويطلب من جميع المستخدمين النشطين إعادة المصادقة.',
'updated_records' => 'السجلات المحدثة',
'vat_not_registered' => 'البائع غير مسجل في ضريبة القيمة المضافة',
'small_company_info' => 'عدم الإفصاح عن ضريبة المبيعات وفقًا للمادة 19 من قانون الضرائب الأمريكي',
'peppol_onboarding' => 'يبدو أن هذه هي المرة الأولى التي تستخدم فيها PEPPOL',
'get_started' => 'البدء',
'configure_peppol' => 'Configure PEPPOL',
'step' => 'خطوة',
'peppol_whitelabel_warning' => 'White-label license required in order to use einvoicing over the PEPPOL network.',
'peppol_plan_warning' => 'Enterprise plan required in order to use einvoicing over the PEPPOL network.',
'peppol_credits_info' => 'Ecredits are required to send and receive einvoices. These are charged on a per document basis.',
'buy_credits' => 'Buy E Credits',
'peppol_successfully_configured' => 'PEPPOL successsfully configured.',
'peppol_not_paid_message' => 'Enterprise plan required for PEPPOL. Please upgrade your plan.',
'peppol_country_not_supported' => 'PEPPOL network not yet available for this country.',
'peppol_disconnect' => 'Disconnect from the PEPPOL network',
'peppol_disconnect_short' => 'Disconnect from PEPPOL.',
'peppol_disconnect_long' => 'Your VAT number will be withdrawn from the PEPPOL network after disconnecting. You will be unable to send or receive edocuments.',
'log_duration_words' => 'مدة تسجيل الوقت بالكلمات',
'log_duration' => 'مدة سجل الوقت',
'merged_vendors' => 'تم دمج البائعين بنجاح',
'hidden_taxes_warning' => 'بعض الضرائب مخفية بسبب إعدادات الضرائب الحالية. :link',
'tax3' => 'الضريبة الثالثة',
'negative_payment_warning' => 'هل أنت متأكد من أنك تريد إنشاء دفعة سلبية؟ لا يمكن استخدام هذه الدفعة كرصيد أو دفعة.',
'currency_Bermudian_Dollar' => 'الدولار البرمودي',
'currency_Central_African_CFA_Franc' => 'الفرنك الوسط أفريقي',
'currency_Congolese_Franc' => 'الفرنك الكونغولي',
'currency_Djiboutian_Franc' => 'فرنك جيبوتي',
'currency_Eritrean_Nakfa' => 'الناكفا الإريترية',
'currency_Falkland_Islands_Pound' => 'Falklan Islands Pound',
'currency_Guinean_Franc' => 'فرنك غيني',
'currency_Iraqi_Dinar' => 'الدينار العراقي',
'currency_Lesotho_Loti' => 'ليسوتو لوتي',
'currency_Mongolian_Tugrik' => 'التوغريك المنغولي',
'currency_Seychellois_Rupee' => 'الروبية السيشيلية',
'currency_Solomon_Islands_Dollar' => 'دولار جزر سليمان',
'currency_Somali_Shilling' => 'شلن صومالي',
'currency_South_Sudanese_Pound' => 'الجنيه الجنوب سوداني',
'currency_Sudanese_Pound' => 'الجنيه السوداني',
'currency_Tajikistani_Somoni' => 'السوموني الطاجيكستاني',
'currency_Turkmenistani_Manat' => 'المانات التركمانستانية',
'currency_Uzbekistani_Som' => 'السوم الأوزباكستاني',
'payment_status_changed' => 'يرجى ملاحظة أن حالة الدفع الخاصة بك قد تم تحديثها. نوصي بتحديث الصفحة لعرض الإصدار الأحدث.',
'credit_status_changed' => 'يرجى ملاحظة أن حالة الائتمان الخاصة بك قد تم تحديثها. نوصي بتحديث الصفحة لعرض الإصدار الأحدث.',
'credit_updated' => 'تم تحديث الائتمان',
'payment_updated' => 'تم تحديث الدفع',
'search_placeholder' => 'ابحث عن الفواتير والعملاء والمزيد',
'invalid_vat_number' => "رقم ضريبة القيمة المضافة غير صالح للبلد المحدد. يجب أن يكون التنسيق عبارة عن رمز البلد متبوعًا برقم فقط، على سبيل المثال، DE123456789",
'acts_as_sender' => 'Acts as Sender',
'acts_as_receiver' => 'Acts as Receiver',
);

return $lang;
Loading

0 comments on commit a352d8d

Please sign in to comment.