2022-06-14 06:55:17 +00:00
< ? php
namespace App\Jobs ;
use Carbon\Carbon ;
use Illuminate\Bus\Queueable ;
use Illuminate\Contracts\Queue\ShouldBeUnique ;
use Illuminate\Contracts\Queue\ShouldQueue ;
use Illuminate\Foundation\Bus\Dispatchable ;
use Illuminate\Queue\InteractsWithQueue ;
use Illuminate\Queue\SerializesModels ;
use Illuminate\Support\Collection ;
use Illuminate\Support\Facades\Config ;
use Illuminate\Support\Facades\Log ;
use App\Models\ { Cost , Service , Site , Supplier };
use App\Traits\Import ;
class ImportCosts implements ShouldQueue
{
use Dispatchable , InteractsWithQueue , Queueable , SerializesModels , Import ;
private const LOGKEY = 'JIC' ;
private Cost $co ;
2022-08-19 05:12:56 +00:00
private Site $site ;
2022-06-14 06:55:17 +00:00
private string $file ;
protected Collection $columns ;
/**
* Create a new job instance .
*
* @ return void
*/
public function __construct ( Site $site , Supplier $so , Carbon $invoice_date , string $file )
{
$this -> file = $file ;
2022-08-19 05:12:56 +00:00
$this -> site = $site ;
2022-06-14 06:55:17 +00:00
2022-08-19 03:52:16 +00:00
$this -> co = Cost :: where ( 'site_id' , $site -> site_id )
2022-06-14 06:55:17 +00:00
-> where ( 'supplier_id' , $so -> id )
-> where ( 'billed_at' , $invoice_date )
-> firstOrNew ();
$this -> co -> active = TRUE ;
2022-08-19 03:52:16 +00:00
$this -> co -> site_id = $site -> site_id ;
2022-06-14 06:55:17 +00:00
$this -> co -> billed_at = $invoice_date ;
$this -> co -> supplier_id = $so -> id ;
$this -> co -> save ();
2022-08-19 03:52:16 +00:00
Cost\Broadband :: where ( 'cost_id' , $this -> co -> id ) -> where ( 'site_id' , $site -> site_id ) -> delete ();
Cost\Phone :: where ( 'cost_id' , $this -> co -> id ) -> where ( 'site_id' , $site -> site_id ) -> delete ();
Cost\Generic :: where ( 'cost_id' , $this -> co -> id ) -> where ( 'site_id' , $site -> site_id ) -> delete ();
2022-06-14 06:55:17 +00:00
// @todo to be stored in supplier config
$headers = [
'INVOICEID' => 'Item ID' ,
'REF' => 'Reference No' ,
'IDTAG' => 'ID Tag' ,
'CATEGORY' => 'Category' ,
'DESC' => 'Item Description' ,
'QUANTITY' => 'Quantity' ,
'PRICEUNIT' => 'Unit Price (inc-GST)' ,
'PRICETOTAL' => 'Total (inc-GST)'
];
$this -> columns = collect ( $headers ) -> transform ( function ( $item ) { return strtolower ( $item ); });
}
/**
* Execute the job .
*
* @ return void
* @ throws \Exception
*/
public function handle ()
{
2022-08-19 05:12:56 +00:00
Config :: set ( 'site' , $this -> site );
2022-06-14 06:55:17 +00:00
$skip = 7 ; // @todo to be stored in supplier config
2022-08-19 05:12:56 +00:00
$file = fopen ( 'storage/app/' . $this -> file , 'r' );
2022-06-14 06:55:17 +00:00
$haveHeader = FALSE ;
$c = 0 ;
while ( ! feof ( $file )) {
$line = stream_get_line ( $file , 0 , " \r \n " );
if ( str_starts_with ( $line , '#' ))
continue ;
// Remove any embedded CR and BOM
$line = str_replace ( " \r " , '' , $line );
$line = preg_replace ( '/^\x{feff}/u' , '' , $line );
if (( $c ++ < $skip ) || ( ! $line ))
continue ;
// The first line is a header.
if ( ! $haveHeader ) {
Log :: debug ( sprintf ( '%s: Input File: %s' , get_class ( $this ), $this -> file ));
Log :: debug ( sprintf ( '%s: Processing columns: %s' , get_class ( $this ), join ( '|' , $this -> setColumns ( $line ) -> toArray ())));
$haveHeader = TRUE ;
continue ;
}
// If the line has a , between two (), then convert the comma to a space.
$x = [];
if ( preg_match ( '#\(.+,.+\)#i' , $line , $x )) {
$replace = str_replace ( ',' , '_' , $x [ 0 ]);
$line = str_replace ( $x [ 0 ], $replace , $line );
//dd($line,$x);
}
$fields = str_getcsv ( trim ( $line ));
if ( is_null ( $x = $this -> getColumnKey ( 'DESC' )) OR empty ( $fields [ $x ]))
continue ;
// The first part of our item description is the service number.
// This should go to a "supplier" function, since all suppliers may show different values in description.
$m = [];
$desc = $fields [ $x ];
// m[1] = Service, m[2] = Desc, m[3] = From Date, m[4] = To Date
preg_match ( '#^([0-9]{10})\s+-\s+(.*)\(([0-9]+\s+[JFMASOND].*\s+[0-9]+)+\s+-\s+([0-9]+\s+[JFMASOND].*\s+[0-9]+)+\)$#' , $fields [ $x ], $m );
2022-06-28 13:20:56 +00:00
if ( count ( $m ) !== 5 ) {
dump ( sprintf ( 'ERROR: Description didnt parse [%s] on line [%d]' , $fields [ $x ], $c ));
continue ;
}
2022-06-14 06:55:17 +00:00
$cost = ( $x = $this -> getColumnKey ( 'PRICETOTAL' )) ? str_replace ([ ',' , '$' ], '' , $fields [ $x ]) : NULL ;
$start_at = Carbon :: createFromFormat ( 'd M Y' , $m [ 3 ]);
$stop_at = Carbon :: createFromFormat ( 'd M Y' , $m [ 4 ]);
$so = Service :: search ( $m [ 1 ]) -> active () -> with ([ 'type' , 'product.type.supplied' ]) -> single ();
if ( $so ) {
// r[1] = Monthly Charge or Extra Charge,r[2] = "On Plan", r[3] = Plan Info
$r = [];
switch ( $so -> category ) {
case 'broadband' :
$to = Cost\Broadband :: where ( 'site_id' , $this -> co -> site_id )
-> where ( 'cost_id' , $this -> co -> id )
-> where ( 'service_broadband_id' , $so -> type -> id )
-> where ( 'start_at' , $start_at )
-> where ( 'end_at' , $stop_at )
-> firstOrNew ();
$to -> service_broadband_id = $so -> type -> id ;
preg_match ( '#^(Monthly Internet Charge|Plan Change Fee|Change billing date refund for Monthly Internet Charge On Plan|First 12 Month VISP broadband plan discount|.*)\s?(On Plan)?\s?(.*)#' , $m [ 2 ], $r );
switch ( $r [ 1 ]) {
case 'Monthly Internet Charge' :
case 'First 12 Month VISP broadband plan discount' :
case 'Change billing date refund for Monthly Internet Charge On Plan' :
$to -> base =+ $cost ;
break ;
case 'Plan Change Fee' :
$to -> excess =+ $cost ;
break ;
default :
dump ([ 'extra charge' => $r ]);
$to -> excess =+ $cost ;
}
break ;
2023-06-16 05:10:36 +00:00
case 'phone' :
2022-06-14 06:55:17 +00:00
$to = Cost\Phone :: where ( 'site_id' , $this -> co -> site_id )
-> where ( 'cost_id' , $this -> co -> id )
-> where ( 'service_phone_id' , $so -> type -> id )
-> where ( 'start_at' , $start_at )
-> where ( 'end_at' , $stop_at )
-> firstOrNew ();
$to -> service_phone_id = $so -> type -> id ;
preg_match ( '#^(Residential VOIP Plan Excess Usage|Virtual FAX Number Monthly Rental|Corporate VOIP Plan Monthly Rental|Residential VOIP Plan Monthly Rental|.*)\s?(.*)#' , $m [ 2 ], $r );
switch ( $r [ 1 ]) {
case 'Residential VOIP Plan Monthly Rental' :
case 'Virtual FAX Number Monthly Rental' :
case 'Corporate VOIP Plan Monthly Rental' :
$to -> base =+ $cost ;
break ;
case 'Residential VOIP Plan Excess Usage' :
$to -> excess =+ $cost ;
$to -> notes = $r [ 2 ];
break ;
default :
dump ([ 'extra charge' => $r ]);
$to -> excess =+ $cost ;
}
break ;
default :
2023-06-16 05:10:36 +00:00
dump ([ 'so' => $so , 'category' => $so -> category , 'line' => $line , 'm' => $m , 'r' => $r ]);
2022-06-14 06:55:17 +00:00
throw new \Exception ( sprintf ( 'ERROR: Service type not handled for service [%s] (%s) on line [%d]' , $m [ 1 ], $so -> category , $c ));
}
} else {
dump ([ 'line' => $line , 'sql' => Service :: search ( $m [ 1 ]) -> active () -> with ([ 'type' , 'product.type.supplied' ]) -> toSql ()]);
$to = Cost\Generic :: where ( 'site_id' , $this -> co -> site_id )
-> where ( 'cost_id' , $this -> co -> id )
-> where ( 'notes' , sprintf ( '%s:%s' , $m [ 1 ], $m [ 2 ]))
-> where ( 'start_at' , $start_at )
-> where ( 'end_at' , $stop_at )
-> firstOrNew ();
$to -> excess =+ $cost ;
$to -> notes = $line ;
}
$to -> site_id = $this -> co -> site_id ;
$to -> cost_id = $this -> co -> id ;
$to -> active = TRUE ;
$to -> start_at = $start_at ;
$to -> end_at = $stop_at ;
// Work out supplier product number
Log :: warning ( sprintf ( '%s:Supplier product ID not matched' , self :: LOGKEY ),[ 'r' => $r ]);
//dd($m[2],$cost,$so->product->type->supplied);
// Work out if this base charge, or extra charge
//dd(['M'=>__METHOD__,'fields'=>$fields,'DESC'=>$this->getColumnKey('DESC'),'desc'=>$desc,'m'=>$m,'sql'=>$so->toSql(),'bindings'=>$so->getBindings(),'so'=>$so]);
$to -> save ();
}
fclose ( $file );
}
}