2024-06-22 18:52:25 +02:00
< ? php
/**
* Invoice Ninja ( https :// invoiceninja . com ) .
*
* @ link https :// github . com / invoiceninja / invoiceninja source repository
*
* @ copyright Copyright ( c ) 2024. Invoice Ninja LLC ( https :// invoiceninja . com )
*
* @ license https :// www . elastic . co / licensing / elastic - license
*/
namespace App\Services\EDocument\Imports ;
use App\Factory\ExpenseFactory ;
use App\Factory\VendorFactory ;
use App\Models\Country ;
use App\Models\Currency ;
use App\Models\Expense ;
use App\Models\Vendor ;
use App\Services\AbstractService ;
use App\Utils\TempFile ;
use App\Utils\Traits\SavesDocuments ;
2024-06-23 09:32:51 +02:00
use Cache ;
2024-06-22 18:52:25 +02:00
use Exception ;
use Mindee\Client ;
use Mindee\Product\Invoice\InvoiceV4 ;
use Illuminate\Http\UploadedFile ;
class MindeeEDocument extends AbstractService
{
use SavesDocuments ;
/**
* @ throws Exception
*/
public function __construct ( public UploadedFile $file )
{
# curl -X POST http://localhost:8000/api/v1/edocument/upload -H "Content-Type: multipart/form-data" -H "X-API-TOKEN: 7tdDdkz987H3AYIWhNGXy8jTjJIoDhkAclCDLE26cTCj1KYX7EBHC66VEitJwWhn" -H "X-Requested-With: XMLHttpRequest" -F _method=PUT -F documents[]=@einvoice.xml
}
/**
* @ throws Exception
*/
public function run () : Expense
{
$user = auth () -> user ();
$api_key = config ( 'services.mindee.api_key' );
if ( ! $api_key )
throw new Exception ( 'Mindee API key not configured' );
2024-06-23 09:32:51 +02:00
$this -> checkLimits ();
2024-06-22 18:52:25 +02:00
2024-06-23 09:32:51 +02:00
// perform parsing
2024-06-22 18:52:25 +02:00
$mindeeClient = new Client ( $api_key );
$inputSource = $mindeeClient -> sourceFromFile ( $this -> file );
2024-06-22 19:58:55 +02:00
$result = $mindeeClient -> parse ( InvoiceV4 :: class , $inputSource );
2024-06-23 09:32:51 +02:00
$this -> incrementRequestCounts ();
2024-06-22 19:58:55 +02:00
/** @var \Mindee\Product\Invoice\InvoiceV4Document $prediction */
$prediction = $result -> document -> inference -> prediction ;
2024-06-22 20:57:11 +02:00
if ( $prediction -> documentType !== 'INVOICE' )
throw new Exception ( 'Unsupported document type' );
2024-06-22 19:58:55 +02:00
$grandTotalAmount = $prediction -> totalAmount -> value ;
$documentno = $prediction -> invoiceNumber -> value ;
$documentdate = $prediction -> date -> value ;
$invoiceCurrency = $prediction -> locale -> currency ;
$country = $prediction -> locale -> country ;
2024-06-22 18:52:25 +02:00
$expense = Expense :: where ( 'amount' , $grandTotalAmount ) -> where ( " transaction_reference " , $documentno ) -> whereDate ( " date " , $documentdate ) -> first ();
if ( empty ( $expense )) {
// The document does not exist as an expense
// Handle accordingly
$expense = ExpenseFactory :: create ( $user -> company () -> id , $user -> id );
$expense -> date = $documentdate ;
$expense -> user_id = $user -> id ;
$expense -> company_id = $user -> company -> id ;
$expense -> public_notes = $documentno ;
$expense -> currency_id = Currency :: whereCode ( $invoiceCurrency ) -> first () -> id ;
$expense -> save ();
2024-06-23 09:32:51 +02:00
$this -> saveDocuments ([
$this -> file ,
TempFile :: UploadedFileFromRaw ( strval ( $result -> document ), $documentno . " _mindee_orc_result.txt " , " text/plain " )
], $expense );
2024-06-22 18:52:25 +02:00
$expense -> saveQuietly ();
$expense -> uses_inclusive_taxes = True ;
$expense -> amount = $grandTotalAmount ;
$counter = 1 ;
2024-06-22 20:57:11 +02:00
foreach ( $prediction -> taxes as $taxesElem ) {
$expense -> { " tax_amount $counter " } = $taxesElem -> amount ;
$expense -> { " tax_rate $counter " } = $taxesElem -> rate ;
$counter ++ ;
2024-06-22 18:52:25 +02:00
}
2024-06-23 09:32:51 +02:00
2024-06-22 20:57:11 +02:00
$vendor = Vendor :: where ( 'email' , $prediction -> supplierEmail ) -> first ();
2024-06-22 18:52:25 +02:00
if ( ! empty ( $vendor )) {
// Vendor found
$expense -> vendor_id = $vendor -> id ;
} else {
$vendor = VendorFactory :: create ( $user -> company () -> id , $user -> id );
2024-06-22 20:57:11 +02:00
$vendor -> name = $prediction -> supplierName ;
$vendor -> email = $prediction -> supplierEmail ;
2024-06-23 09:32:51 +02:00
$vendor -> currency_id = Currency :: whereCode ( $invoiceCurrency ) -> first () ? -> id ;
2024-06-22 19:58:55 +02:00
$vendor -> phone = $prediction -> supplierPhoneNumber ;
2024-06-23 09:32:51 +02:00
// $vendor->address1 = $address_1; // TODO: we only have the full address string from mindee returned
2024-06-22 20:57:11 +02:00
// $vendor->address2 = $address_2;
// $vendor->city = $city;
// $vendor->postal_code = $postcode;
2024-06-23 09:32:51 +02:00
$vendor -> country_id = Country :: where ( 'iso_3166_2' , $country ) -> first () ? -> id || Country :: where ( 'iso_3166_3' , $country ) -> first () ? -> id || null ; // could be 2 or 3 length
2024-06-22 18:52:25 +02:00
$vendor -> save ();
$expense -> vendor_id = $vendor -> id ;
}
$expense -> transaction_reference = $documentno ;
} else {
// The document exists as an expense
// Handle accordingly
nlog ( " Document already exists " );
$expense -> private_notes = $expense -> private_notes . ctrans ( " texts.edocument_import_already_exists " , [ " date " => time ()]);
}
$expense -> save ();
return $expense ;
}
2024-06-23 09:32:51 +02:00
private function checkLimits ()
{
$user = auth () -> user ();
Cache :: add ( 'mindeeTotalDailyRequests' , 0 , now () -> endOfDay ());
Cache :: add ( 'mindeeTotalMonthlyRequests' , 0 , now () -> endOfMonth ());
Cache :: add ( 'mindeeAccountDailyRequests' . $user -> company -> account -> id , 0 , now () -> endOfDay ());
Cache :: add ( 'mindeeAccountMonthlyRequests' . $user -> company -> account -> id , 0 , now () -> endOfMonth ());
if ( config ( 'services.mindee.daily_limit' ) != 0 && Cache :: get ( 'mindeeTotalDailyRequests' ) > config ( 'services.mindee.daily_limit' ))
throw new Exception ( 'Mindee daily limit reached' );
if ( config ( 'services.mindee.monthly_limit' ) != 0 && Cache :: get ( 'mindeeTotalMonthlyRequests' ) > config ( 'services.mindee.monthly_limit' ))
throw new Exception ( 'Mindee monthly limit reached' );
if ( config ( 'services.mindee.account_daily_limit' ) != 0 && Cache :: get ( 'mindeeAccountDailyRequests' . $user -> company -> account -> id ) > config ( 'services.mindee.account_daily_limit' ))
throw new Exception ( 'Mindee daily limit reached for account: ' . $user -> company -> account -> id );
if ( config ( 'services.mindee.account_monthly_limit' ) != 0 && Cache :: get ( 'mindeeAccountMonthlyRequests' . $user -> company -> account -> id ) > config ( 'services.mindee.account_monthly_limit' ))
throw new Exception ( 'Mindee monthly limit reached for account: ' . $user -> company -> account -> id );
}
private function incrementRequestCounts ()
{
$user = auth () -> user ();
Cache :: increment ( 'mindeeTotalDailyRequests' );
Cache :: increment ( 'mindeeTotalMonthlyRequests' );
Cache :: increment ( 'mindeeAccountDailyRequests' . $user -> company -> account -> id );
Cache :: increment ( 'mindeeAccountMonthlyRequests' . $user -> company -> account -> id );
}
2024-06-22 18:52:25 +02:00
}