229 lines
7.0 KiB
PHP
229 lines
7.0 KiB
PHP
<?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;
|
|
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;
|
|
Config::set('site',$site);
|
|
|
|
$this->co = Cost::where('site_id',$site->id)
|
|
->where('supplier_id',$so->id)
|
|
->where('billed_at',$invoice_date)
|
|
->firstOrNew();
|
|
$this->co->active = TRUE;
|
|
$this->co->site_id = $site->id;
|
|
$this->co->billed_at = $invoice_date;
|
|
$this->co->supplier_id = $so->id;
|
|
$this->co->save();
|
|
|
|
Cost\Broadband::where('cost_id',$this->co->id)->where('site_id',$site->id)->delete();
|
|
Cost\Phone::where('cost_id',$this->co->id)->where('site_id',$site->id)->delete();
|
|
Cost\Generic::where('cost_id',$this->co->id)->where('site_id',$site->id)->delete();
|
|
|
|
// @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()
|
|
{
|
|
$skip = 7; // @todo to be stored in supplier config
|
|
|
|
$file = fopen($this->file,'r');
|
|
$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);
|
|
|
|
if (count($m) !== 5)
|
|
throw new \Exception(sprintf('ERROR: Description didnt parse [%s] on line [%d]',$fields[$x],$c));
|
|
|
|
$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;
|
|
|
|
case 'phone':
|
|
$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:
|
|
dump(['so'=>$so,'line'=>$line]);
|
|
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);
|
|
}
|
|
}
|