Basic DHL implementation, Refactor redundant code

This commit is contained in:
Andreas Palm 2022-11-14 22:29:42 +01:00
parent d676a1b09a
commit 8ad45ed723
44 changed files with 1051 additions and 4196 deletions

View File

@ -0,0 +1,14 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class Bank
{
public string $accountOwner;
public string $bankName;
public string $iban;
public string $note1;
public string $note2;
public ?string $bic;
public ?string $accountreference;
}

View File

@ -0,0 +1,10 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class Communication
{
public ?string $phone;
public ?string $email;
public ?string $contactPerson;
}

View File

@ -0,0 +1,10 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class Contact
{
public ?Communication $Communication;
public ?NativeAddress $Address;
public ?Name $Name;
}

View File

@ -0,0 +1,18 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class Country
{
public ?string $country;
public string $countryISOCode;
public ?string $state;
public static function Create(string $isoCode, ?string $state = null):Country {
$obj = new Country();
$obj->countryISOCode = $isoCode;
$obj->state = $state;
return $obj;
}
}

View File

@ -0,0 +1,14 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class CreateShipmentOrderRequest
{
public Version $Version;
public ShipmentOrder $ShipmentOrder;
public ?string $labelResponseType;
public ?string $groupProfileName;
public ?string $labelFormat;
public ?string $labelFormatRetoure;
public ?string $combinedPrinting;
}

View File

@ -0,0 +1,10 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class CreateShipmentOrderResponse
{
public Version $Version;
public Statusinformation $Status;
public ?CreationState $CreationState;
}

View File

@ -0,0 +1,11 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class CreationState
{
public string $sequenceNumber;
public ?string $shipmentNumber;
public ?string $returnShipmentNumber;
public LabelData $LabelData;
}

View File

@ -0,0 +1,14 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class Customer
{
public Name $Name;
public ?string $vatID;
public string $EKP;
public NativeAddress $Address;
public Contact $Contact;
public ?Bank $Bank;
public ?string $note;
}

View File

@ -0,0 +1,9 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class DeleteShipmentOrderRequest
{
public Version $Version;
public string $shipmentNumber;
}

View File

@ -0,0 +1,10 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class DeleteShipmentOrderResponse
{
public Version $Version;
public Statusinformation $Status;
public ?DeletionState $DeletionState;
}

View File

@ -0,0 +1,9 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class DeletionState
{
public string $shipmentNumber;
public Statusinformation $Status;
}

View File

@ -0,0 +1,12 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class DeliveryAddress
{
public ?NativeAddress $NativeAddress;
public ?Postfiliale $PostOffice;
public ?PackStation $PackStation;
public ?string $streetNameCode;
public ?string $streetNumberCode;
}

View File

@ -0,0 +1,11 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class Dimension
{
public int $length;
public int $width;
public int $height;
public ?string $unit;
}

View File

@ -0,0 +1,13 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class ExportDocPosition
{
public string $description;
public string $countryCodeOrigin;
public string $customsTariffNumber;
public int $amount;
public float $netWeightInKG;
public float $customsValue;
}

View File

@ -0,0 +1,34 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class ExportDocument
{
const TYPE_PRESENT = 'PRESENT';
const TYPE_DOCUMENT = 'DOCUMENT';
const TYPE_COMMERCIAL_GOODS = 'COMMERCIAL_GOODS';
const TYPE_COMMERCIAL_SAMPLE = 'COMMERCIAL_SAMPLE';
const TYPE_RETURN_OF_GOODS= 'RETURN_OF_GOODS';
const TYPE_OTHER = 'OTHER';
const TERMS_DDP = 'DDP';
const TERMS_DXV = 'DXV';
const TERMS_DAP = 'DAP';
const TERMS_DDX = 'DDX';
const TERMS_CPT = 'CPT';
public ?string $invoiceNumber;
public string $exportType;
public ?string $exportTypeDescription;
public ?string $termsOfTrade;
public string $placeOfCommital;
public ?float $additionalFee;
public ?string $customsCurrency;
public ?string $permitNumber;
public ?string $attestationNumber;
public ?string $addresseesCustomsReference;
public ?string $sendersCustomsReference;
public ?bool $WithElectronicExportNtfctn;
/** @var ExportDocPosition[] $ExportDocPosition */
public array $ExportDocPosition;
}

View File

@ -0,0 +1,17 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class LabelData
{
public Statusinformation $Status;
public ?string $shipmentNumber;
public ?string $labelUrl;
public ?string $labelData;
public ?string $returnLabelUrl;
public ?string $returnLabelData;
public ?string $exportLabelUrl;
public ?string $exportLabelData;
public ?string $codLabelUrl;
public ?string $codLabelData;
}

View File

@ -0,0 +1,10 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class Name
{
public string $name1;
public ?string $name2;
public ?string $name3;
}

View File

@ -0,0 +1,19 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class NativeAddress
{
public string $streetName;
public ?string $streetNumber;
/**
* @var string[]
*/
public array $addressAddition;
public ?string $dispatchingInformation;
public string $zip;
public string $city;
public ?string $province;
public ?Country $Origin;
}

View File

@ -0,0 +1,12 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class NativeAddressNew
{
public string $streetName;
public ?string $streetNumber;
public string $zip;
public string $city;
public ?Country $Origin;
}

View File

@ -0,0 +1,13 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class PackStation
{
public string $postNumber;
public string $packstationNumber;
public string $zip;
public string $city;
public ?string $province;
public ?Country $Origin;
}

View File

@ -0,0 +1,12 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class Postfiliale
{
public string $postfilialeNumber;
public string $postNumber;
public string $zip;
public string $city;
public ?Country $Origin;
}

View File

@ -0,0 +1,12 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class Receiver
{
public string $name1;
public ?NativeAddress $Address;
public ?PackStation $Packstation;
public ?Postfiliale $Postfiliale;
public ?Communication $Communication;
}

View File

@ -0,0 +1,22 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class Shipment
{
public ShipmentDetails $ShipmentDetails;
public Shipper $Shipper;
public string $ShipperReference;
public Receiver $Receiver;
public ?Shipper $ReturnReceiver;
public ?ExportDocument $ExportDocument;
public ?string $feederSystem;
public function __construct()
{
$this->ShipmentDetails = new ShipmentDetails();
$this->Shipper = new Shipper();
$this->ShipperReference = '';
$this->Receiver = new Receiver();
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
use DateTimeImmutable;
class ShipmentDetails
{
public string $product;
public string $accountNumber;
public string $customerReference;
private string $shipmentDate;
public string $costCentre;
public string $returnShipmentAccountNumber;
public string $returnShipmentReference;
public ShipmentItem $ShipmentItem;
public ShipmentService $Service;
public ShipmentNotification $Notification;
public Bank $BankData;
public function SetShipmentDate(DateTimeImmutable $date): void {
$this->shipmentDate = $date->format('Y-m-d');
}
public function GetShipmentDate(): DateTimeImmutable {
return DateTimeImmutable::createFromFormat('Y-m-d', $this->shipmentDate);
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class ShipmentItem
{
public float $weightInKG;
public ?int $lengthInCM;
public ?int $widthInCM;
public ?int $heightInCM;
}

View File

@ -0,0 +1,9 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class ShipmentNotification
{
public string $recipientEmailAddress;
public ?string $templateId;
}

View File

@ -0,0 +1,10 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class ShipmentOrder
{
public string $sequenceNumber;
public Shipment $Shipment;
public ?Serviceconfiguration $PrintOnlyIfCodeable;
}

View File

@ -0,0 +1,7 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class ShipmentService
{
}

View File

@ -0,0 +1,16 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class Shipper
{
public Name $Name;
public NativeAddressNew $Address;
public ?Communication $Communication;
public function __construct()
{
$this->Name = new Name();
$this->Address = new NativeAddressNew();
}
}

View File

@ -0,0 +1,9 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class Status
{
public string $statuscode;
public string $statusDescription;
}

View File

@ -0,0 +1,9 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class StatusElement
{
public string $statusElement;
public string $statusMessage;
}

View File

@ -0,0 +1,13 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class Statusinformation
{
public int $statusCode;
public string $statusText;
public array|string $statusMessage;
public string $statusType;
public StatusElement $errorMessage;
public StatusElement $warningMessage;
}

View File

@ -0,0 +1,10 @@
<?php
namespace Xentral\Carrier\Dhl\Data;
class Version
{
public string $majorRelease;
public string $minorRelease;
public ?string $build;
}

View File

@ -0,0 +1,70 @@
<?php
namespace Xentral\Carrier\Dhl;
use SoapClient;
use SoapHeader;
use Xentral\Carrier\Dhl\Data\CreateShipmentOrderRequest;
use Xentral\Carrier\Dhl\Data\CreateShipmentOrderResponse;
use Xentral\Carrier\Dhl\Data\CreationState;
use Xentral\Carrier\Dhl\Data\LabelData;
use Xentral\Carrier\Dhl\Data\Shipment;
use Xentral\Carrier\Dhl\Data\ShipmentOrder;
use Xentral\Carrier\Dhl\Data\Statusinformation;
use Xentral\Carrier\Dhl\Data\Version;
class DhlApi
{
private SoapClient $soapClient;
private const SANDBOX_URL = 'https://cig.dhl.de/services/sandbox/soap';
private const PRODUCTION_URL = 'https://cig.dhl.de/services/production/soap';
private const NAMESPACE_CIS = 'http://dhl.de/webservice/cisbase';
public function __construct(string $user, string $signature)
{
$this->soapClient = new SoapClient(__DIR__ . '/Wsdl/geschaeftskundenversand-api-3.4.0.wsdl', [
'login' => 'ewsp',
'password' => 'rZ*twrzJ5@wr&$',
'location' => self::SANDBOX_URL,
'trace' => 1,
'connection_timeout' => 30,
'classmap' => [
'CreateShipmentOrderResponse' => CreateShipmentOrderResponse::class,
'CreationState' => CreationState::class,
'LabelData' => LabelData::class,
'Statusinformation' => Statusinformation::class,
'Version' => Version::class,
]
]);
$authHeader = new SoapHeader(self::NAMESPACE_CIS, 'Authentification', [
'user' => $user,
'signature' => $signature
]);
$this->soapClient->__setSoapHeaders($authHeader);
}
public function CreateShipment(Shipment $shipment): CreateShipmentOrderResponse|string
{
$request = new CreateShipmentOrderRequest();
$request->Version = $this->getVersion();
$request->ShipmentOrder = new ShipmentOrder();
$request->ShipmentOrder->Shipment = $shipment;
$request->ShipmentOrder->sequenceNumber = '1';
$request->labelResponseType = "B64";
try {
$response = $this->soapClient->createShipmentOrder($request);
return $response;
} catch (\SoapFault $e) {
return $e->getMessage();
}
}
private function getVersion() {
$version = new Version();
$version->majorRelease = '3';
$version->minorRelease = '4';
return $version;
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace Xentral\Modules\ShippingMethod\Model;
class CreateShipmentResult
{
public bool $Success = false;
public array $Errors = [];
public ?string $Label;
public ?string $ExportDocuments;
public ?string $TrackingNumber;
public ?string $TrackingUrl;
}

View File

@ -0,0 +1,13 @@
<?php
namespace Xentral\Modules\ShippingMethod\Model;
class CustomsInfo
{
const CUSTOMS_TYPE_GIFT = 0;
const CUSTOMS_TYPE_DOCUMENTS = 1;
const CUSTOMS_TYPE_GOODS = 2;
const CUSTOMS_TYPE_SAMPLE = 3;
const CUSTOMS_TYPE_RETURN = 4;
}

View File

@ -0,0 +1,57 @@
<?php
namespace Xentral\Modules\ShippingMethod\Model;
class Product
{
const SERVICE_COD = 'cod';
const SERVICE_PREMIUM = 'premium';
public string $Id;
public string $Name;
public float $LengthMin = 0;
public float $LengthMax = 500;
public float $WidthMin = 0;
public float $WidthMax = 500;
public float $HeightMin = 0;
public float $HeightMax = 500;
public float $WeightMin = 0;
public float $WeightMax = 100;
public array $AvailableServices = [];
public static function Create(string $id, string $name):Product {
$obj = new Product();
$obj->Id = $id;
$obj->Name = $name;
return $obj;
}
public function WithLength(float $min, float $max): Product {
$this->LengthMin = $min;
$this->LengthMax = $max;
return $this;
}
public function WithWidth(float $min, float $max): Product {
$this->WidthMin = $min;
$this->WidthMax = $max;
return $this;
}
public function WithHeight(float $min, float $max): Product {
$this->HeightMin = $min;
$this->HeightMax = $max;
return $this;
}
public function WithWeight(float $min, float $max): Product {
$this->WeightMin = $min;
$this->WeightMax = $max;
return $this;
}
public function WithServices(array $services): Product {
$this->AvailableServices = $services;
return $this;
}
}

View File

@ -1,5 +1,11 @@
<?php <?php
abstract class Versanddienstleister {
use Xentral\Modules\ShippingMethod\Model\CreateShipmentResult;
use Xentral\Modules\ShippingMethod\Model\CustomsInfo;
use Xentral\Modules\ShippingMethod\Model\Product;
abstract class Versanddienstleister
{
protected int $id; protected int $id;
protected Application $app; protected Application $app;
protected string $type; protected string $type;
@ -26,91 +32,83 @@ abstract class Versanddienstleister {
$this->settings = json_decode($row['einstellungen_json']); $this->settings = json_decode($row['einstellungen_json']);
} }
public function isEtikettenDrucker(): bool { public function isEtikettenDrucker(): bool
{
return false; return false;
} }
public function GetAdressdaten($id, $sid) public abstract function GetName(): string;
public function GetAdressdaten($id, $sid): array
{ {
$auftragId = $lieferscheinId = $rechnungId = $versandId = 0; $auftragId = $lieferscheinId = $rechnungId = $versandId = 0;
if($sid==='rechnung') if ($sid === 'rechnung')
$rechnungId = $id; $rechnungId = $id;
if($sid==='lieferschein') { if ($sid === 'lieferschein') {
$lieferscheinId = $id; $lieferscheinId = $id;
$auftragId = $this->app->DB->Select("SELECT auftragid FROM lieferschein WHERE id=$lieferscheinId LIMIT 1"); $auftragId = $this->app->DB->Select("SELECT auftragid FROM lieferschein WHERE id=$lieferscheinId LIMIT 1");
$rechnungId = $this->app->DB->Select("SELECT id FROM rechnung WHERE lieferschein = '$lieferscheinId' LIMIT 1"); $rechnungId = $this->app->DB->Select("SELECT id FROM rechnung WHERE lieferschein = '$lieferscheinId' LIMIT 1");
if($rechnungId <= 0) if ($rechnungId <= 0)
$rechnungId = $this->app->DB->Select("SELECT rechnungid FROM lieferschein WHERE id='$lieferscheinId' LIMIT 1"); $rechnungId = $this->app->DB->Select("SELECT rechnungid FROM lieferschein WHERE id='$lieferscheinId' LIMIT 1");
} }
if($sid==='versand') if ($sid === 'versand') {
{
$versandId = $id; $versandId = $id;
$lieferscheinId = $this->app->DB->Select("SELECT lieferschein FROM versand WHERE id='$versandId' LIMIT 1"); $lieferscheinId = $this->app->DB->Select("SELECT lieferschein FROM versand WHERE id='$versandId' LIMIT 1");
$rechnungId = $this->app->DB->Select("SELECT rechnung FROM versand WHERE id='$versandId' LIMIT 1"); $rechnungId = $this->app->DB->Select("SELECT rechnung FROM versand WHERE id='$versandId' LIMIT 1");
$sid = 'lieferschein'; $sid = 'lieferschein';
} }
if ($auftragId <= 0 && $rechnungId > 0) if ($auftragId <= 0 && $rechnungId > 0)
$auftragId = $this->app->DB->Select("SELECT auftragid FROM rechnung WHERE id=$rechnungId LIMIT 1"); $auftragId = $this->app->DB->Select("SELECT auftragid FROM rechnung WHERE id=$rechnungId LIMIT 1");
if($sid==='rechnung' || $sid==='lieferschein' || $sid==='adresse') if ($sid === 'rechnung' || $sid === 'lieferschein' || $sid === 'adresse') {
{
$docArr = $this->app->DB->SelectRow("SELECT * FROM `$sid` WHERE id = $id LIMIT 1"); $docArr = $this->app->DB->SelectRow("SELECT * FROM `$sid` WHERE id = $id LIMIT 1");
$ret['addressId'] = $docArr['adresse'];
$ret['auftragId'] = $auftragId;
$ret['rechnungId'] = $rechnungId;
$ret['lieferscheinId'] = $lieferscheinId;
$addressfields = ['name', 'adresszusatz', 'abteilung', 'ansprechpartner', 'unterabteilung', 'ort', 'plz', $addressfields = ['name', 'adresszusatz', 'abteilung', 'ansprechpartner', 'unterabteilung', 'ort', 'plz',
'strasse', 'land', 'telefon', 'email']; 'strasse', 'land'];
$ret = array_filter($docArr, fn($key)=>in_array($key, $addressfields), ARRAY_FILTER_USE_KEY); $ret['original'] = array_filter($docArr, fn($key) => in_array($key, $addressfields), ARRAY_FILTER_USE_KEY);
$name2 = trim($docArr['adresszusatz']); $ret['name'] = empty(trim($docArr['ansprechpartner'])) ? trim($docArr['name']) : trim($docArr['ansprechpartner']);
$abt = 0; $ret['companyname'] = !empty(trim($docArr['ansprechpartner'])) ? trim($docArr['name']) : '';
if($name2==='') $ret['address2'] = join(';', array_filter([
{ $docArr['abteilung'],
$name2 = trim($docArr['abteilung']); $docArr['unterabteilung'],
$abt=1; $docArr['adresszusatz']
} ], fn(string $item) => !empty(trim($item))));
$name3 = trim($docArr['ansprechpartner']);
if($name3==='' && $abt!==1){
$name3 = trim($docArr['abteilung']);
}
//unterabteilung versuchen einzublenden
if($name2==='') {
$name2 = trim($docArr['unterabteilung']);
} else if ($name3==='') {
$name3 = trim($docArr['unterabteilung']);
}
if($name3!=='' && $name2==='') { $ret['city'] = $docArr['ort'];
$name2=$name3; $ret['zip'] = $docArr['plz'];
$name3=''; $ret['country'] = $docArr['land'];
} $ret['phone'] = $docArr['telefon'];
$ret['name2'] = $name2; $ret['email'] = $docArr['email'];
$ret['name3'] = $name3;
$strasse = trim($docArr['strasse']); $strasse = trim($docArr['strasse']);
$ret['streetwithnumber'] = $strasse; $ret['streetwithnumber'] = $strasse;
$hausnummer = trim($this->app->erp->ExtractStreetnumber($strasse)); $hausnummer = trim($this->app->erp->ExtractStreetnumber($strasse));
$strasse = trim(str_replace($hausnummer,'',$strasse)); $strasse = trim(str_replace($hausnummer, '', $strasse));
$strasse = str_replace('.','',$strasse); $strasse = str_replace('.', '', $strasse);
if($strasse=='') if ($strasse == '') {
{
$strasse = trim($hausnummer); $strasse = trim($hausnummer);
$hausnummer = ''; $hausnummer = '';
} }
$ret['strasse'] = $strasse; $ret['street'] = $strasse;
$ret['hausnummer'] = $hausnummer; $ret['streetnumber'] = $hausnummer;
} }
// wenn rechnung im spiel entweder durch versand oder direkt rechnung // wenn rechnung im spiel entweder durch versand oder direkt rechnung
if($rechnungId >0) if ($rechnungId > 0) {
{ $invoice_data = $this->app->DB->SelectRow("SELECT zahlungsweise, soll, belegnr FROM rechnung WHERE id='$rechnungId' LIMIT 1");
$invoice_data = $this->app->DB->SelectRow("SELECT zahlungsweise, soll, belegnr FROM rechnung WHERE id='$rechnungId' LIMIT 1");
$ret['zahlungsweise'] = $invoice_data['zahlungsweise']; $ret['zahlungsweise'] = $invoice_data['zahlungsweise'];
$ret['betrag'] = $invoice_data['soll']; $ret['betrag'] = $invoice_data['soll'];
$ret['invoice_number'] = $invoice_data['belegnr']; $ret['invoice_number'] = $invoice_data['belegnr'];
if($invoice_data['zahlungsweise']==='nachnahme'){ if ($invoice_data['zahlungsweise'] === 'nachnahme') {
$ret['nachnahme'] = true; $ret['nachnahme'] = true;
} }
} }
@ -118,10 +116,10 @@ abstract class Versanddienstleister {
$sql = "SELECT $sql = "SELECT
lp.bezeichnung, lp.bezeichnung,
lp.menge, lp.menge,
coalesce(nullif(lp.zolltarifnummer, ''), nullif(rp.zolltarifnummer, ''), nullif(a.zolltarifnummer, '')) zolltarifnummer, coalesce(nullif(lp.zolltarifnummer, ''), nullif(rp.zolltarifnummer, ''), nullif(a.zolltarifnummer, '')) as zolltarifnummer,
coalesce(nullif(lp.herkunftsland, ''), nullif(rp.herkunftsland, ''), nullif(a.herkunftsland, '')) herkunftsland, coalesce(nullif(lp.herkunftsland, ''), nullif(rp.herkunftsland, ''), nullif(a.herkunftsland, '')) as herkunftsland,
coalesce(nullif(lp.zolleinzelwert, '0'), rp.preis *(1-rp.rabatt/100)) zolleinzelwert, coalesce(nullif(lp.zolleinzelwert, '0'), rp.preis *(1-rp.rabatt/100)) as zolleinzelwert,
coalesce(nullif(lp.zolleinzelgewicht, 0), a.gewicht) zolleinzelgewicht, coalesce(nullif(lp.zolleinzelgewicht, 0), a.gewicht) as zolleinzelgewicht,
lp.zollwaehrung lp.zollwaehrung
FROM lieferschein_position lp FROM lieferschein_position lp
JOIN artikel a on lp.artikel = a.id JOIN artikel a on lp.artikel = a.id
@ -131,10 +129,9 @@ abstract class Versanddienstleister {
ORDER BY lp.sort"; ORDER BY lp.sort";
$ret['positions'] = $this->app->DB->SelectArr($sql); $ret['positions'] = $this->app->DB->SelectArr($sql);
if($sid==="lieferschein"){ if ($sid === "lieferschein") {
$standardkg = $this->app->erp->VersandartMindestgewicht($lieferscheinId); $standardkg = $this->app->erp->VersandartMindestgewicht($lieferscheinId);
} } else {
else{
$standardkg = $this->app->erp->VersandartMindestgewicht(); $standardkg = $this->app->erp->VersandartMindestgewicht();
} }
$ret['weight'] = $standardkg; $ret['weight'] = $standardkg;
@ -155,7 +152,8 @@ abstract class Versanddienstleister {
* *
* @return array * @return array
*/ */
public function AdditionalSettings(): array { public function AdditionalSettings(): array
{
return []; return [];
} }
@ -168,73 +166,60 @@ abstract class Versanddienstleister {
public function RenderAdditionalSettings(string $target, array $form): void public function RenderAdditionalSettings(string $target, array $form): void
{ {
$fields = $this->AdditionalSettings(); $fields = $this->AdditionalSettings();
if($this->app->Secure->GetPOST('speichern')) if ($this->app->Secure->GetPOST('speichern')) {
{ $json = $this->app->DB->Select("SELECT einstellungen_json FROM versandarten WHERE id = '" . $this->id . "' LIMIT 1");
$json = $this->app->DB->Select("SELECT einstellungen_json FROM versandarten WHERE id = '".$this->id."' LIMIT 1"); $modul = $this->app->DB->Select("SELECT modul FROM versandarten WHERE id = '" . $this->id . "' LIMIT 1");
$modul = $this->app->DB->Select("SELECT modul FROM versandarten WHERE id = '".$this->id."' LIMIT 1"); if (!empty($json)) {
if(!empty($json))
{
$json = @json_decode($json, true); $json = @json_decode($json, true);
}else{ } else {
$json = array(); $json = array();
foreach($fields as $name => $val) foreach ($fields as $name => $val) {
{ if (isset($val['default'])) {
if(isset($val['default']))
{
$json[$name] = $val['default']; $json[$name] = $val['default'];
} }
} }
} }
if(empty($json)) if (empty($json)) {
{
$json = null; $json = null;
} }
foreach($fields as $name => $val) foreach ($fields as $name => $val) {
{
if($modul === $this->app->Secure->GetPOST('modul_name')) if ($modul === $this->app->Secure->GetPOST('modul_name')) {
{ $json[$name] = $this->app->Secure->GetPOST($name, '', '', 1);
$json[$name] = $this->app->Secure->GetPOST($name, '','', 1);
} }
if(isset($val['replace'])) if (isset($val['replace'])) {
{ switch ($val['replace']) {
switch($val['replace'])
{
case 'lieferantennummer': case 'lieferantennummer':
$json[$name] = $this->app->erp->ReplaceLieferantennummer(1,$json[$name],1); $json[$name] = $this->app->erp->ReplaceLieferantennummer(1, $json[$name], 1);
break; break;
} }
} }
} }
$json_str = $this->app->DB->real_escape_string(json_encode($json)); $json_str = $this->app->DB->real_escape_string(json_encode($json));
$this->app->DB->Update("UPDATE versandarten SET einstellungen_json = '$json_str' WHERE id = '".$this->id."' LIMIT 1"); $this->app->DB->Update("UPDATE versandarten SET einstellungen_json = '$json_str' WHERE id = '" . $this->id . "' LIMIT 1");
} }
$html = ''; $html = '';
foreach($fields as $name => $val) // set missing default values foreach ($fields as $name => $val) // set missing default values
{ {
if(isset($val['default']) && !isset($form[$name])) if (isset($val['default']) && !isset($form[$name])) {
{
$form[$name] = $val['default']; $form[$name] = $val['default'];
} }
} }
foreach($fields as $name => $val) foreach ($fields as $name => $val) {
{ if (isset($val['heading']))
if(isset($val['heading'])) $html .= '<tr><td colspan="2"><b>' . html_entity_decode($val['heading']) . '</b></td></tr>';
$html .= '<tr><td colspan="2"><b>'.html_entity_decode($val['heading']).'</b></td></tr>';
$html .= '<tr><td>'.($val['bezeichnung'] ?? $name).'</td><td>'; $html .= '<tr><td>' . ($val['bezeichnung'] ?? $name) . '</td><td>';
if(isset($val['replace'])) if (isset($val['replace'])) {
{ switch ($val['replace']) {
switch($val['replace'])
{
case 'lieferantennummer': case 'lieferantennummer':
$form[$name] = $this->app->erp->ReplaceLieferantennummer(0,$form[$name],0); $form[$name] = $this->app->erp->ReplaceLieferantennummer(0, $form[$name], 0);
$this->app->YUI->AutoComplete($name, 'lieferant', 1); $this->app->YUI->AutoComplete($name, 'lieferant', 1);
break; break;
case 'shop': case 'shop':
$form[$name] .= ($form[$name]?' '.$this->app->DB->Select("SELECT bezeichnung FROM shopexport WHERE id = '".(int)$form[$name]."'"):''); $form[$name] .= ($form[$name] ? ' ' . $this->app->DB->Select("SELECT bezeichnung FROM shopexport WHERE id = '" . (int)$form[$name] . "'") : '');
$this->app->YUI->AutoComplete($name, 'shopnameid'); $this->app->YUI->AutoComplete($name, 'shopnameid');
break; break;
case 'etiketten': case 'etiketten':
@ -242,41 +227,38 @@ abstract class Versanddienstleister {
break; break;
} }
} }
switch($val['typ'] ?? 'text') switch ($val['typ'] ?? 'text') {
{
case 'textarea': case 'textarea':
$html .= '<textarea name="'.$name.'" id="'.$name.'">'.($form[$name] ?? '').'</textarea>'; $html .= '<textarea name="' . $name . '" id="' . $name . '">' . ($form[$name] ?? '') . '</textarea>';
break; break;
case 'checkbox': case 'checkbox':
$html .= '<input type="checkbox" name="'.$name.'" id="'.$name.'" value="1" '.($form[$name] ?? false ? ' checked="checked" ':'').' />'; $html .= '<input type="checkbox" name="' . $name . '" id="' . $name . '" value="1" ' . ($form[$name] ?? false ? ' checked="checked" ' : '') . ' />';
break; break;
case 'select': case 'select':
$html .= $this->app->Tpl->addSelect('return', $name, $name, $val['optionen'], $form[$name]); $html .= $this->app->Tpl->addSelect('return', $name, $name, $val['optionen'], $form[$name]);
break; break;
case 'submit': case 'submit':
if(isset($val['text'])) if (isset($val['text']))
$html .= '<form method="POST"><input type="submit" name="'.$name.'" value="'.$val['text'].'"></form>'; $html .= '<form method="POST"><input type="submit" name="' . $name . '" value="' . $val['text'] . '"></form>';
break; break;
case 'custom': case 'custom':
if(isset($val['function'])) if (isset($val['function'])) {
{
$tmpfunction = $val['function']; $tmpfunction = $val['function'];
if(method_exists($this, $tmpfunction)) if (method_exists($this, $tmpfunction)) {
{
$html .= $this->$tmpfunction(); $html .= $this->$tmpfunction();
} }
} }
break; break;
default: default:
$html .= '<input type="text"' $html .= '<input type="text"'
.(!empty($val['size'])?' size="'.$val['size'].'"':'') . (!empty($val['size']) ? ' size="' . $val['size'] . '"' : '')
.(!empty($val['placeholder'])?' placeholder="'.$val['placeholder'].'"':'') . (!empty($val['placeholder']) ? ' placeholder="' . $val['placeholder'] . '"' : '')
.' name="'.$name.'" id="'.$name.'" value="'.(isset($form[$name])?htmlspecialchars($form[$name]):'').'" />'; . ' name="' . $name . '" id="' . $name . '" value="' . (isset($form[$name]) ? htmlspecialchars($form[$name]) : '') . '" />';
break; break;
} }
if(isset($val['info']) && $val['info']) if (isset($val['info']) && $val['info'])
$html .= ' <i>'.$val['info'].'</i>'; $html .= ' <i>' . $val['info'] . '</i>';
$html .= '</td></tr>'; $html .= '</td></tr>';
} }
$this->app->Tpl->Add($target, $html); $this->app->Tpl->Add($target, $html);
@ -290,21 +272,20 @@ abstract class Versanddienstleister {
*/ */
public function ValidateSettings(array &$form): array public function ValidateSettings(array &$form): array
{ {
return []; return [];
} }
/** /**
* @param string $tracking * @param string $tracking
* @param int $versand * @param int $versand
* @param int $lieferschein * @param int $lieferschein
*/ */
public function SetTracking($tracking,$versand=0,$lieferschein=0, $trackingLink = '') public function SetTracking($tracking, $versand = 0, $lieferschein = 0, $trackingLink = '')
{ {
//if($versand > 0) $this->app->DB->Update("UPDATE versand SET tracking=CONCAT(tracking,if(tracking!='',';',''),'".$tracking."') WHERE id='$versand' LIMIT 1"); //if($versand > 0) $this->app->DB->Update("UPDATE versand SET tracking=CONCAT(tracking,if(tracking!='',';',''),'".$tracking."') WHERE id='$versand' LIMIT 1");
$this->app->User->SetParameter('versand_lasttracking',$tracking); $this->app->User->SetParameter('versand_lasttracking', $tracking);
$this->app->User->SetParameter('versand_lasttracking_link',$trackingLink); $this->app->User->SetParameter('versand_lasttracking_link', $trackingLink);
$this->app->User->SetParameter('versand_lasttracking_versand', $versand); $this->app->User->SetParameter('versand_lasttracking_versand', $versand);
$this->app->User->SetParameter('versand_lasttracking_lieferschein', $lieferschein); $this->app->User->SetParameter('versand_lasttracking_lieferschein', $lieferschein);
} }
@ -314,17 +295,17 @@ abstract class Versanddienstleister {
*/ */
public function deleteTrackingFromUserdata($tracking) public function deleteTrackingFromUserdata($tracking)
{ {
if(empty($tracking)) { if (empty($tracking)) {
return; return;
} }
$trackingUser = !empty($this->app->User) && method_exists($this->app->User,'GetParameter')? $trackingUser = !empty($this->app->User) && method_exists($this->app->User, 'GetParameter') ?
$this->app->User->GetParameter('versand_lasttracking'):''; $this->app->User->GetParameter('versand_lasttracking') : '';
if(empty($trackingUser) || $trackingUser !== $tracking) { if (empty($trackingUser) || $trackingUser !== $tracking) {
return; return;
} }
$this->app->User->SetParameter('versand_lasttracking',''); $this->app->User->SetParameter('versand_lasttracking', '');
$this->app->User->SetParameter('versand_lasttracking_link',''); $this->app->User->SetParameter('versand_lasttracking_link', '');
$this->app->User->SetParameter('versand_lasttracking_versand', ''); $this->app->User->SetParameter('versand_lasttracking_versand', '');
$this->app->User->SetParameter('versand_lasttracking_lieferschein', ''); $this->app->User->SetParameter('versand_lasttracking_lieferschein', '');
} }
@ -341,21 +322,84 @@ abstract class Versanddienstleister {
/** /**
* @param string $tracking * @param string $tracking
* @param int $notsend * @param int $notsend
* @param string $link * @param string $link
* @param string $rawlink * @param string $rawlink
* *
* @return bool * @return bool
*/ */
public function Trackinglink($tracking, &$notsend, &$link, &$rawlink) { public function Trackinglink($tracking, &$notsend, &$link, &$rawlink)
{
$notsend = 0; $notsend = 0;
$rawlink = ''; $rawlink = '';
$link = ''; $link = '';
return true; return true;
} }
public function Paketmarke(string $target, string $docType, int $docId): void { public function Paketmarke(string $target, string $docType, int $docId): void
{
$address = $this->GetAdressdaten($docId, $docType);
if (isset($_SERVER['HTTP_CONTENT_TYPE']) && ($_SERVER['HTTP_CONTENT_TYPE'] === 'application/json')) {
$json = json_decode(file_get_contents('php://input'));
$ret = [];
if ($json->submit == 'print') {
$result = $this->CreateShipment($json, $address);
if ($result->Success) {
$sql = "INSERT INTO versand
(adresse, lieferschein, versandunternehmen, gewicht, tracking, tracking_link, anzahlpakete)
VALUES
({$address['addressId']}, {$address['lieferscheinId']}, '$this->type',
'$json->weight', '$result->TrackingNumber', '$result->TrackingUrl', 1)";
print_r($sql);
$this->app->DB->Insert($sql);
$filename = $this->app->erp->GetTMP() . join('_', [$this->type, 'Label', $result->TrackingNumber]) . '.pdf';
file_put_contents($filename, $result->Label);
$this->app->printer->Drucken($this->labelPrinterId, $filename);
if (isset($result->ExportDocuments)) {
$filename = $this->app->erp->GetTMP() . join('_', [$this->type, 'ExportDoc', $result->TrackingNumber]) . '.pdf';
file_put_contents($filename, $result->ExportDocuments);
$this->app->printer->Drucken($this->documentPrinterId, $filename);
}
$ret['messages'][] = ['class' => 'info', 'text' => "Paketmarke wurde erfolgreich erstellt: $result->TrackingNumber"];
} else {
$ret['messages'] = array_map(fn(string $item) => ['class' => 'error', 'text' => $item], array_unique($result->Errors));
}
}
header('Content-Type: application/json');
echo json_encode($ret);
$this->app->ExitXentral();
}
$address['sendungsart'] = CustomsInfo::CUSTOMS_TYPE_GOODS;
$products = $this->GetShippingProducts();
$products = array_combine(array_column($products, 'Id'), $products);
$address['product'] = $products[0]->Id ?? '';
$json['form'] = $address;
$json['countries'] = $this->app->erp->GetSelectLaenderliste();
$json['products'] = $products;
$json['customs_shipment_types'] = [
CustomsInfo::CUSTOMS_TYPE_GIFT => 'Geschenk',
CustomsInfo::CUSTOMS_TYPE_DOCUMENTS => 'Dokumente',
CustomsInfo::CUSTOMS_TYPE_GOODS => 'Handelswaren',
CustomsInfo::CUSTOMS_TYPE_SAMPLE => 'Erprobungswaren',
CustomsInfo::CUSTOMS_TYPE_RETURN => 'Rücksendung'
];
$json['messages'] = [];
$json['form']['services'] = [
Product::SERVICE_PREMIUM => false
];
$this->app->Tpl->Set('JSON', json_encode($json));
$this->app->Tpl->Set('CARRIERNAME', $this->GetName());
$this->app->Tpl->Parse($target, 'createshipment.tpl');
} }
public abstract function CreateShipment(object $json, array $address): CreateShipmentResult;
/**
* @return Product[]
*/
public abstract function GetShippingProducts(): array;
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,57 +1,57 @@
<div class="container-fluid" id="sendcloudapp"> <div class="container-fluid" id="createshipmentapp">
<form action="" method="post" v-on:submit.prevent="submit"> <form action="" method="post" v-on:submit.prevent="submit">
<div class="row"> <div class="row">
<div v-for="msg in messages" :class="msg.class">{{msg.text}}</div> <div v-for="msg in messages" :class="msg.class">{{msg.text}}</div>
<div> <div>
<h1>{|Paketmarken Drucker f&uuml;r|} SendCloud</h1> <h1>{|Paketmarken Drucker f&uuml;r|} [CARRIERNAME]</h1>
</div> </div>
<div class="col-md-4"> <div class="col-md-4">
<h2>{|Empf&auml;nger|}</h2> <h2>{|Empf&auml;nger|}</h2>
<table> <table>
<tr> <tr>
<td>{|Name|}:</td> <td>{|Name|}:</td>
<td><input type="text" size="36" v-model="form.l_name"></td> <td><input type="text" size="36" v-model.trim="form.name"></td>
</tr> </tr>
<tr> <tr>
<td>{|Firmenname|}:</td> <td>{|Firmenname|}:</td>
<td><input type="text" size="36" v-model="form.l_companyname"></td> <td><input type="text" size="36" v-model.trim="form.companyname"></td>
</tr> </tr>
<tr> <tr>
<td>{|Strasse/Hausnummer|}:</td> <td>{|Strasse/Hausnummer|}:</td>
<td> <td>
<input type="text" size="30" v-model="form.strasse"> <input type="text" size="30" v-model.trim="form.street">
<input type="text" size="5" v-model="form.hausnummer"> <input type="text" size="5" v-model.trim="form.streetnumber">
</td> </td>
</tr> </tr>
<tr> <tr>
<td>{|Adresszeile 2|}:</td> <td>{|Adresszeile 2|}:</td>
<td><input type="text" size="36" v-model="form.l_address2"></td> <td><input type="text" size="36" v-model.trim="form.address2"></td>
</tr> </tr>
<tr> <tr>
<td>{|PLZ/Ort|}:</td> <td>{|PLZ/Ort|}:</td>
<td><input type="text" size="5" v-model="form.plz"> <td><input type="text" size="5" v-model.trim="form.zip">
<input type="text" size="30" v-model="form.ort"> <input type="text" size="30" v-model.trim="form.city">
</td> </td>
</tr> </tr>
<tr> <tr>
<td>{|Bundesland|}:</td> <td>{|Bundesland|}:</td>
<td><input type="text" size="36" v-model="form.bundesland"></td> <td><input type="text" size="36" v-model.trim="form.state"></td>
</tr> </tr>
<tr> <tr>
<td>{|Land|}:</td> <td>{|Land|}:</td>
<td> <td>
<select v-model="form.land"> <select v-model="form.country" required>
<option v-for="(value, key) in countries" :value="key">{{value}}</option> <option v-for="(value, key) in countries" :value="key">{{value}}</option>
</select> </select>
</td> </td>
</tr> </tr>
<tr> <tr>
<td>{|E-Mail|}:</td> <td>{|E-Mail|}:</td>
<td><input type="text" size="36" v-model="form.email"></td> <td><input type="text" size="36" v-model.trim="form.email"></td>
</tr> </tr>
<tr> <tr>
<td>{|Telefon|}:</td> <td>{|Telefon|}:</td>
<td><input type="text" size="36" v-model="form.telefon"></td> <td><input type="text" size="36" v-model.trim="form.phone"></td>
</tr> </tr>
</table> </table>
@ -61,39 +61,39 @@
<table> <table>
<tr> <tr>
<td>{|Name|}</td> <td>{|Name|}</td>
<td>{{form.name}}</td> <td>{{form.original.name}}</td>
</tr> </tr>
<tr> <tr>
<td>{|Ansprechpartner|}</td> <td>{|Ansprechpartner|}</td>
<td>{{form.ansprechpartner}}</td> <td>{{form.original.ansprechpartner}}</td>
</tr> </tr>
<tr> <tr>
<td>{|Abteilung|}</td> <td>{|Abteilung|}</td>
<td>{{form.abteilung}}</td> <td>{{form.original.abteilung}}</td>
</tr> </tr>
<tr> <tr>
<td>{|Unterabteilung|}</td> <td>{|Unterabteilung|}</td>
<td>{{form.unterabteilung}}</td> <td>{{form.original.unterabteilung}}</td>
</tr> </tr>
<tr> <tr>
<td>{|Adresszusatz|}</td> <td>{|Adresszusatz|}</td>
<td>{{form.adresszusatz}}</td> <td>{{form.original.adresszusatz}}</td>
</tr> </tr>
<tr> <tr>
<td>{|Strasse|}</td> <td>{|Strasse|}</td>
<td>{{form.streetwithnumber}}</td> <td>{{form.original.strasse}}</td>
</tr> </tr>
<tr> <tr>
<td>{|PLZ/Ort|}</td> <td>{|PLZ/Ort|}</td>
<td>{{form.plz}} {{form.ort}}</td> <td>{{form.original.plz}} {{form.original.ort}}</td>
</tr> </tr>
<tr> <tr>
<td>{|Bundesland|}</td> <td>{|Bundesland|}</td>
<td>{{form.bundesland}}</td> <td>{{form.original.bundesland}}</td>
</tr> </tr>
<tr> <tr>
<td>{|Land|}</td> <td>{|Land|}</td>
<td>{{form.land}}</td> <td>{{form.original.land}}</td>
</tr> </tr>
</table> </table>
</div> </div>
@ -102,28 +102,32 @@
<table> <table>
<tr> <tr>
<td>{|Gewicht (in kg)|}:</td> <td>{|Gewicht (in kg)|}:</td>
<td><input type="text" v-model="form.weight"></td> <td><input type="text" v-model.number="form.weight"></td>
</tr> </tr>
<tr> <tr>
<td>{|H&ouml;he (in cm)|}:</td> <td>{|H&ouml;he (in cm)|}:</td>
<td><input type="text" size="10" v-model="form.height"></td> <td><input type="text" size="10" v-model.number="form.height"></td>
</tr> </tr>
<tr> <tr>
<td>{|Breite (in cm)|}:</td> <td>{|Breite (in cm)|}:</td>
<td><input type="text" size="10" v-model="form.width"></td> <td><input type="text" size="10" v-model.number="form.width"></td>
</tr> </tr>
<tr> <tr>
<td>{|L&auml;nge (in cm)|}:</td> <td>{|L&auml;nge (in cm)|}:</td>
<td><input type="text" size="10" v-model="form.length"></td> <td><input type="text" size="10" v-model.number="form.length"></td>
</tr> </tr>
<tr> <tr>
<td>{|Produkt|}:</td> <td>{|Produkt|}:</td>
<td> <td>
<select v-model="form.method"> <select v-model="form.product">
<option v-for="(value, key, index) in methods" :value="key">{{value}}</option> <option v-for="prod in products" :value="prod.Id">{{prod.Name}}</option>
</select> </select>
</td> </td>
</tr> </tr>
<tr v-if="serviceAvailable('premium')">
<td>{|Premium|}:</td>
<td><input type="checkbox" v-model="form.services.premium"></td>
</tr>
</table> </table>
</div> </div>
<div class="clearfix"></div> <div class="clearfix"></div>
@ -161,25 +165,23 @@
<th>{|Herkunftsland|}</th> <th>{|Herkunftsland|}</th>
<th>{|Einzelwert|}</th> <th>{|Einzelwert|}</th>
<th>{|Einzelgewicht|}</th> <th>{|Einzelgewicht|}</th>
<th>{|Währung|}</th>
<th>{|Gesamtwert|}</th> <th>{|Gesamtwert|}</th>
<th>{|Gesamtgewicht|}</th> <th>{|Gesamtgewicht|}</th>
<th><a v-on:click="addPosition"><img src="themes/new/images/add.png"></a></</th> <th><a v-on:click="addPosition"><img src="themes/new/images/add.png"></a></</th>
</tr> </tr>
<tr v-for="(pos, index) in form.positions"> <tr v-for="(pos, index) in form.positions">
<td><input type="text" v-model="pos.bezeichnung" required></td> <td><input type="text" v-model.trim="pos.bezeichnung" required></td>
<td><input type="text" v-model="pos.menge" required></td> <td><input type="text" v-model.number="pos.menge" required></td>
<td><input type="text" v-model="pos.zolltarifnummer" required></td> <td><input type="text" v-model.trim="pos.zolltarifnummer" required></td>
<td><input type="text" v-model="pos.herkunftsland" required></td> <td><input type="text" v-model.trim="pos.herkunftsland" required></td>
<td><input type="text" v-model="pos.zolleinzelwert" required></td> <td><input type="text" v-model.number="pos.zolleinzelwert" required></td>
<td><input type="text" v-model="pos.zolleinzelgewicht" required></td> <td><input type="text" v-model.number="pos.zolleinzelgewicht" required></td>
<td><input type="text" v-model="pos.zollwaehrung" required></td>
<td>{{Number(pos.menge*pos.zolleinzelwert || 0).toFixed(2)}}</td> <td>{{Number(pos.menge*pos.zolleinzelwert || 0).toFixed(2)}}</td>
<td>{{Number(pos.menge*pos.zolleinzelgewicht || 0).toFixed(3)}}</td> <td>{{Number(pos.menge*pos.zolleinzelgewicht || 0).toFixed(3)}}</td>
<td><a v-on:click="deletePosition(index)"><img src="themes/new/images/delete.svg"></a></td> <td><a v-on:click="deletePosition(index)"><img src="themes/new/images/delete.svg"></a></td>
</tr> </tr>
<tr> <tr>
<td colspan="7"></td> <td colspan="6"></td>
<td>{{total_value.toFixed(2)}}</td> <td>{{total_value.toFixed(2)}}</td>
<td>{{total_weight.toFixed(3)}}</td> <td>{{total_weight.toFixed(3)}}</td>
</tr> </tr>
@ -187,33 +189,27 @@
</div> </div>
<div> <div>
<input class="btnGreen" type="submit" value="{|Paketmarke drucken|}" name="drucken">&nbsp; <input class="btnGreen" type="submit" value="{|Paketmarke drucken|}" name="drucken">&nbsp;
<input type="button" value="{|Andere Versandart auswählen|}" name="anders">&nbsp; <!--<input type="button" value="{|Andere Versandart auswählen|}" name="anders">&nbsp;-->
</div> </div>
</div> </div>
</form> </form>
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
const sendcloudApp = new Vue({ const createshipmentapp = new Vue({
el: '#sendcloudapp', el: '#createshipmentapp',
data: { data: [JSON],
form: [JSON],
countries: [JSON_COUNTRIES],
methods: [JSON_METHODS],
customs_shipment_types: [JSON_CUSTOMS_SHIPMENT_TYPES],
messages: []
},
computed: { computed: {
total_value() { total_value() {
let sum = 0; let sum = 0;
for(const pos of this.form.positions) { for(const pos of this.form.positions) {
sum += pos.menge * pos.zolleinzelwert; sum += (pos.menge * pos.zolleinzelwert) || 0;
} }
return sum; return sum;
}, },
total_weight() { total_weight() {
let sum = 0; let sum = 0;
for(const pos of this.form.positions) { for(const pos of this.form.positions) {
sum += pos.menge * pos.zolleinzelgewicht; sum += (pos.menge * pos.zolleinzelgewicht) || 0;
} }
return sum; return sum;
} }
@ -235,6 +231,11 @@
}, },
deletePosition: function(index) { deletePosition: function(index) {
this.form.positions.splice(index, 1); this.form.positions.splice(index, 1);
},
serviceAvailable: function(service) {
if (!this.products.hasOwnProperty(this.form.product))
return false;
return this.products[this.form.product].AvailableServices.indexOf(service) >= 0;
} }
} }
}) })

View File

@ -0,0 +1,169 @@
<?php
/**
*
*/
use Xentral\Carrier\Dhl\Data\Communication;
use Xentral\Carrier\Dhl\Data\Country;
use Xentral\Carrier\Dhl\Data\CreateShipmentOrderResponse;
use Xentral\Carrier\Dhl\Data\NativeAddress;
use Xentral\Carrier\Dhl\Data\Shipment;
use Xentral\Carrier\Dhl\Data\ShipmentItem;
use Xentral\Carrier\Dhl\DhlApi;
use Xentral\Modules\ShippingMethod\Model\CreateShipmentResult;
use Xentral\Modules\ShippingMethod\Model\Product;
require_once(dirname(__DIR__).'/class.versanddienstleister.php');
class Versandart_dhl extends Versanddienstleister{
public function GetName():string
{
return 'DHL';
}
public function AdditionalSettings(): array
{
return [
'user' => array('typ' => 'text', 'bezeichnung' => 'Benutzer:', 'info' => 'geschaeftskunden_api (Versenden/Intraship-Benutzername)'),
'signature' => array('typ' => 'text', 'bezeichnung' => 'Signature:', 'info' => 'Dhl_ep_test1 (Versenden/IntrashipPasswort)'),
'ekp' => array('typ' => 'text', 'bezeichnung' => 'EKP', 'info' => '5000000000 (gültige DHL Kundennummer)'),
'accountnumber' => array('typ' => 'text', 'bezeichnung' => 'Abrechnungsnummer Paket:'),
'accountnumber_int' => array('typ' => 'text', 'bezeichnung' => 'Abrechnungsnummer Paket International:'),
'accountnumber_euro' => array('typ' => 'text', 'bezeichnung' => 'Abrechnungsnummer Europaket:'),
'accountnumber_connect' => array('typ' => 'text', 'bezeichnung' => 'Abrechnungsnummer Paket Connect:'),
'accountnumber_wp' => array('typ' => 'text', 'bezeichnung' => 'Abrechnungsnummer Warenpost:'),
'accountnumber_wpint' => array('typ' => 'text', 'bezeichnung' => 'Abrechnungsnummer Warenpost International:'),
// 'intraship_retourenaccount' => array('typ' => 'text', 'bezeichnung' => 'Retouren Account:', 'info' => '14 Stellige DHL-Retoure Abrechnungsnummer'),
// 'intraship_retourenlabel' => array('typ' => 'checkbox', 'bezeichnung' => 'Vorauswahl Retourenlabel:', 'info' => 'Druckt Retourenlabel mit'),
'sender_name1' => array('typ' => 'text', 'bezeichnung' => 'Versender Firma:'),
'sender_street' => array('typ' => 'text', 'bezeichnung' => 'Versender Strasse:'),
'sender_streetnumber' => array('typ' => 'text', 'bezeichnung' => 'Versender Strasse Nr.:'),
'sender_zip' => array('typ' => 'text', 'bezeichnung' => 'Versender PLZ:'),
'sender_city' => array('typ' => 'text', 'bezeichnung' => 'Versender Stadt:'),
'sender_country' => array('typ' => 'text', 'bezeichnung' => 'Versender ISO Code:', 'info' => 'DE'),
'sender_email' => array('typ' => 'text', 'bezeichnung' => 'Versender E-Mail:'),
'sender_phone' => array('typ' => 'text', 'bezeichnung' => 'Versender Telefon:'),
'sender_web' => array('typ' => 'text', 'bezeichnung' => 'Versender Web:'),
'sender_contact_person' => array('typ' => 'text', 'bezeichnung' => 'Versender Ansprechpartner:'),
'cod_account_owner' => array('typ' => 'text', 'bezeichnung' => 'Nachnahme Kontoinhaber:'),
'cod_bank_name' => array('typ' => 'text', 'bezeichnung' => 'Nachnahme Bank Name:'),
'cod_account_iban' => array('typ' => 'text', 'bezeichnung' => 'Nachnahme IBAN:'),
'cod_account_bic' => array('typ' => 'text', 'bezeichnung' => 'Nachnahme BIC:'),
'cod_extra_fee' => array('typ' => 'text', 'bezeichnung' => 'Nachnahme Gebühr:', 'info' => 'z.B. 2,00 wird auf Rechnungsbetrag addiert, da DHL dies als extra Gebühr für sich behält'),
'weight' => array('typ' => 'text', 'bezeichnung' => 'Standard Gewicht:', 'info' => 'in KG'),
'length' => array('typ' => 'text', 'bezeichnung' => 'Standard Länge:', 'info' => 'in cm'),
'width' => array('typ' => 'text', 'bezeichnung' => 'Standard Breite:', 'info' => 'in cm'),
'height' => array('typ' => 'text', 'bezeichnung' => 'Standard Höhe:', 'info' => 'in cm'),
'product' => array('typ' => 'text', 'bezeichnung' => 'Standard Produkt:', 'info' => 'z.B. in DE: V01PAK oder AT: V86PARCEL'),
'use_premium' => array('typ' => 'checkbox', 'bezeichnung' => 'Premiumversand verwenden:'),
/*
'intraship_vorausverfuegung' => array('typ' => 'select', 'bezeichnung' => 'Vorausverf&uuml;gung: ', 'optionen' => array('-' => 'keine Vorausverf&uuml;gung', 'IMMEDIATE' => 'Sofortige R&uuml;cksendung an den Absender', 'AFTER_DEADLINE' => 'R&uuml;cksenden an den Absender nach Ablauf der Frist', 'ABANDONMENT' => 'Preisgabe des Pakets durch den Absender (entgeltfrei)')),
'sperrgut' => array('typ' => 'checkbox', 'bezeichnung' => 'Sperrgut:'),
'keineversicherung' => array('typ' => 'checkbox', 'bezeichnung' => 'Extra Versicherung ausschalten:', 'info' => 'Option muss von Hand im Paketmarkendialog gesetzt werden.'),
'leitcodierung' => array('typ' => 'checkbox', 'bezeichnung' => 'Leitcodierung aktivieren:'),
'use_shipping_article_from_order_on_export' => ['typ' => 'checkbox', 'bezeichnung' => 'Bei Export Porto aus Auftrag senden:'],
'autotracking' => array('typ' => 'checkbox', 'bezeichnung' => 'Tracking übernehmen:'),
'log' => array('typ' => 'checkbox', 'bezeichnung' => 'Logging')*/
];
}
public function CreateShipment(object $json, array $address): CreateShipmentResult
{
$shipment = new Shipment();
$shipment->ShipmentDetails->product = $json->product;
$shipment->ShipmentDetails->accountNumber = '22222222220101';
$shipment->ShipmentDetails->SetShipmentDate(new DateTimeImmutable('today'));
$shipment->ShipmentDetails->ShipmentItem = new ShipmentItem();
$shipment->ShipmentDetails->ShipmentItem->weightInKG = $json->weight ?? 0;
$shipment->ShipmentDetails->ShipmentItem->lengthInCM = $json->length;
$shipment->ShipmentDetails->ShipmentItem->widthInCM = $json->width;
$shipment->ShipmentDetails->ShipmentItem->heightInCM = $json->height;
$shipment->Shipper->Name->name1 = $this->settings->sender_name1 ?? '';
$shipment->Shipper->Address->streetName = $this->settings->sender_street ?? '';
$shipment->Shipper->Address->streetNumber = $this->settings->sender_streetnumber;
$shipment->Shipper->Address->zip = $this->settings->sender_zip ?? '';
$shipment->Shipper->Address->city = $this->settings->sender_city ?? '';
$shipment->Shipper->Address->Origin = Country::Create($this->settings->sender_country ?? 'DE');
$shipment->Shipper->Communication = new Communication();
$shipment->Shipper->Communication->phone = $this->settings->sender_phone;
$shipment->Shipper->Communication->email = $this->settings->sender_email;
$shipment->Shipper->Communication->contactPerson = $this->settings->sender_contact_person;
$shipment->Receiver->name1 = $json->name;
$shipment->Receiver->Address = new NativeAddress();
$shipment->Receiver->Address->streetName = $json->street ?? '';
$shipment->Receiver->Address->streetNumber = $json->streetnumber ?? '';
$shipment->Receiver->Address->city = $json->city ?? '';
$shipment->Receiver->Address->zip = $json->zip ?? '';
$shipment->Receiver->Address->Origin = Country::Create($json->country ?? 'DE', $json->state);
$shipment->Receiver->Communication = new Communication();
$shipment->Receiver->Communication->email = $json->email;
$shipment->Receiver->Communication->phone = $json->phone;
$api = new DhlApi($this->settings->user, $this->settings->signature);
$ret = new CreateShipmentResult();
$result = $api->CreateShipment($shipment);
if (!$result instanceof CreateShipmentOrderResponse) {
$ret->Errors[] = $result;
return $ret;
}
if ($result->Status->statusCode === 0) {
$ret->Success = true;
$ret->TrackingNumber = $result->CreationState->shipmentNumber;
$ret->TrackingUrl = sprintf('https://www.dhl.de/de/privatkunden/pakete-empfangen/verfolgen.html?piececode=%s', $ret->TrackingNumber);
if (isset($result->CreationState->LabelData->labelData))
$ret->Label = base64_decode($result->CreationState->LabelData->labelData);
if (isset($result->CreationState->LabelData->exportLabelData))
$ret->ExportDocuments = base64_decode($result->CreationState->LabelData->exportLabelData);
} else {
if (is_array($result->CreationState->LabelData->Status->statusMessage))
$ret->Errors = $result->CreationState->LabelData->Status->statusMessage;
else
$ret->Errors[] = $result->CreationState->LabelData->Status->statusMessage;
}
return $ret;
}
public function GetShippingProducts(): array
{
$result = [];
$result[] = Product::Create('V01PAK', 'DHL Paket')
->WithLength(15, 120)
->WithWidth(11, 60)
->WithHeight(1, 60)
->WithWeight(0.01, 31.5);
$result[] = Product::Create('V53WPAK', 'DHL Paket International')
->WithLength(15, 120)
->WithWidth(11, 60)
->WithHeight(1, 60)
->WithWeight(0.01, 31.5)
->WithServices([Product::SERVICE_PREMIUM]);
$result[] = Product::Create('V54EPAK', 'DHL Europaket')
->WithLength(15, 120)
->WithWidth(11, 60)
->WithHeight(3.5, 60)
->WithWeight(0.01, 31.5);
$result[] = Product::Create('V55PAK', 'DHL Paket Connect')
->WithLength(15, 120)
->WithWidth(11, 60)
->WithHeight(3.5, 60)
->WithWeight(0.01, 31.5);
$result[] = Product::Create('V62WP', 'DHL Warenpost')
->WithLength(10, 35)
->WithWidth(7, 25)
->WithHeight(0.1, 5)
->WithWeight(0.01, 1);
$result[] = Product::Create('V66WPI', 'DHL Warenpost International')
->WithLength(10, 35)
->WithWidth(7, 25)
->WithHeight(0.1, 10)
->WithWeight(0.01, 1)
->WithServices([Product::SERVICE_PREMIUM]);
return $result;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,8 @@ use Xentral\Carrier\SendCloud\Data\SenderAddress;
use Xentral\Carrier\SendCloud\Data\ShippingProduct; use Xentral\Carrier\SendCloud\Data\ShippingProduct;
use Xentral\Carrier\SendCloud\Data\ShippingMethod; use Xentral\Carrier\SendCloud\Data\ShippingMethod;
use Xentral\Carrier\SendCloud\SendcloudApiException; use Xentral\Carrier\SendCloud\SendcloudApiException;
use Xentral\Modules\ShippingMethod\Model\CreateShipmentResult;
use Xentral\Modules\ShippingMethod\Model\Product;
require_once dirname(__DIR__) . '/class.versanddienstleister.php'; require_once dirname(__DIR__) . '/class.versanddienstleister.php';
@ -25,6 +27,11 @@ class Versandart_sendcloud extends Versanddienstleister
$this->api = new SendCloudApi($this->settings->public_key, $this->settings->private_key); $this->api = new SendCloudApi($this->settings->public_key, $this->settings->private_key);
} }
public function GetName(): string
{
return "SendCloud";
}
protected function FetchOptionsFromApi() protected function FetchOptionsFromApi()
{ {
if (isset($this->options)) if (isset($this->options))
@ -49,13 +56,6 @@ class Versandart_sendcloud extends Versanddienstleister
$this->options['products'][0] = ''; $this->options['products'][0] = '';
$this->options['selectedProduct'] = $shippingProducts[$this->settings->shipping_product] ?? []; $this->options['selectedProduct'] = $shippingProducts[$this->settings->shipping_product] ?? [];
natcasesort($this->options['products']); natcasesort($this->options['products']);
$this->options['customs_shipment_types'] = [
0 => 'Geschenk',
1 => 'Dokumente',
2 => 'Kommerzielle Waren',
3 => 'Erprobungswaren',
4 => 'Rücksendung'
];
} }
public function AdditionalSettings(): array public function AdditionalSettings(): array
@ -66,102 +66,77 @@ class Versandart_sendcloud extends Versanddienstleister
'private_key' => ['typ' => 'text', 'bezeichnung' => 'API Private Key:'], 'private_key' => ['typ' => 'text', 'bezeichnung' => 'API Private Key:'],
'sender_address' => ['typ' => 'select', 'bezeichnung' => 'Absender-Adresse:', 'optionen' => $this->options['senders']], 'sender_address' => ['typ' => 'select', 'bezeichnung' => 'Absender-Adresse:', 'optionen' => $this->options['senders']],
'shipping_product' => ['typ' => 'select', 'bezeichnung' => 'Versand-Produkt:', 'optionen' => $this->options['products']], 'shipping_product' => ['typ' => 'select', 'bezeichnung' => 'Versand-Produkt:', 'optionen' => $this->options['products']],
'default_customs_shipment_type' => ['typ' => 'select', 'bezeichnung' => 'Sendungsart:', 'optionen' => $this->options['customs_shipment_types']],
]; ];
} }
public function Paketmarke(string $target, string $docType, int $docId): void public function CreateShipment(object $json, array $address): CreateShipmentResult
{ {
$address = $this->GetAdressdaten($docId, $docType); $parcel = new ParcelCreation();
$parcel->SenderAddressId = $this->settings->sender_address;
if (isset($_SERVER['HTTP_CONTENT_TYPE']) && ($_SERVER['HTTP_CONTENT_TYPE'] === 'application/json')) { $parcel->ShippingMethodId = $json->product;
$json = json_decode(file_get_contents('php://input')); $parcel->Name = $json->name;
$response = []; $parcel->CompanyName = $json->companyname;
if ($json->submit == 'print') { $parcel->Country = $json->country;
header('Content-Type: application/json'); $parcel->PostalCode = $json->zip;
$parcel = new ParcelCreation(); $parcel->City = $json->city;
$parcel->SenderAddressId = $this->settings->sender_address; $parcel->Address = $json->street;
$parcel->ShippingMethodId = $json->method; $parcel->Address2 = $json->address2;
$parcel->Name = $json->l_name; $parcel->HouseNumber = $json->streetnumber;
$parcel->CompanyName = $json->l_companyname; $parcel->EMail = $json->email;
$parcel->Country = $json->land; $parcel->Telephone = $json->phone;
$parcel->PostalCode = $json->plz; $parcel->CountryState = $json->state;
$parcel->City = $json->ort; $parcel->CustomsInvoiceNr = $json->invoice_number;
$parcel->Address = $json->strasse; $parcel->CustomsShipmentType = $json->shipment_type;
$parcel->Address2 = $json->l_address2; $parcel->TotalInsuredValue = $json->total_insured_value;
$parcel->HouseNumber = $json->hausnummer; $parcel->OrderNumber = $json->order_number;
$parcel->EMail = $json->email; foreach ($json->positions as $pos) {
$parcel->Telephone = $json->telefon; $item = new ParcelItem();
$parcel->CountryState = $json->bundesland; $item->HsCode = $pos->zolltarifnummer;
$parcel->CustomsInvoiceNr = $json->invoice_number; $item->Description = $pos->bezeichnung;
$parcel->CustomsShipmentType = $json->sendungsart; $item->Quantity = $pos->menge;
$parcel->TotalInsuredValue = $json->total_insured_value; $item->OriginCountry = $pos->herkunftsland;
$parcel->OrderNumber = $json->order_number; $item->Price = $pos->zolleinzelwert;
foreach ($json->positions as $pos) { $item->Weight = $pos->zolleinzelgewicht * 1000;
$item = new ParcelItem(); $parcel->ParcelItems[] = $item;
$item->HsCode = $pos->zolltarifnummer;
$item->Description = $pos->bezeichnung;
$item->Quantity = $pos->menge;
$item->OriginCountry = $pos->herkunftsland;
$item->Price = $pos->zolleinzelwert;
$item->Weight = $pos->zolleinzelgewicht * 1000;
$parcel->ParcelItems[] = $item;
}
$parcel->Weight = floatval($json->weight) * 1000;
try {
$result = $this->api->CreateParcel($parcel);
if ($result instanceof ParcelResponse) {
$sql = "INSERT INTO versand
(adresse, lieferschein, versandunternehmen, gewicht, tracking, tracking_link, anzahlpakete)
VALUES
({$address['addressId']}, {$address['lieferscheinId']}, '$this->type',
'$json->weight', '$result->TrackingNumber', '$result->TrackingUrl', 1)";
$this->app->DB->Insert($sql);
$response['messages'][] = ['class' => 'info', 'text' => "Paketmarke wurde erfolgreich erstellt: $result->TrackingNumber"];
$doc = $result->GetDocumentByType(Document::TYPE_LABEL);
$filename = $this->app->erp->GetTMP() . join('_', ['Sendcloud', $doc->Type, $doc->Size, $result->TrackingNumber]) . '.pdf';
file_put_contents($filename, $this->api->DownloadDocument($doc));
$this->app->printer->Drucken($this->labelPrinterId, $filename);
$doc = $result->GetDocumentByType(Document::TYPE_CN23);
$filename = $this->app->erp->GetTMP() . join('_', ['Sendcloud', $doc->Type, $doc->Size, $result->TrackingNumber]) . '.pdf';
file_put_contents($filename, $this->api->DownloadDocument($doc));
$this->app->printer->Drucken($this->documentPrinterId, $filename);
} else {
$response['messages'][] = ['class' => 'error', 'text' => $result];
}
echo json_encode($response);
} catch (SendcloudApiException $e) {
$this->app->Tpl->addMessage('error', $e->getMessage());
}
$this->app->ExitXentral();
}
} }
$parcel->Weight = floatval($json->weight) * 1000;
$ret = new CreateShipmentResult();
try {
$result = $this->api->CreateParcel($parcel);
if ($result instanceof ParcelResponse) {
$ret->Success = true;
$ret->TrackingNumber = $result->TrackingNumber;
$ret->TrackingUrl = $result->TrackingUrl;
$address['l_name'] = empty(trim($address['ansprechpartner'])) ? trim($address['name']) : trim($address['ansprechpartner']); $doc = $result->GetDocumentByType(Document::TYPE_LABEL);
$address['l_companyname'] = !empty(trim($address['ansprechpartner'])) ? trim($address['name']) : ''; $ret->Label = $this->api->DownloadDocument($doc);
$address['l_address2'] = join(';', array_filter([
$address['abteilung'],
$address['unterabteilung'],
$address['adresszusatz']
], fn(string $item) => !empty(trim($item))));
$doc = $result->GetDocumentByType(Document::TYPE_CN23);
$ret->ExportDocuments = $this->api->DownloadDocument($doc);
} else {
$ret->Errors[] = $result;
}
} catch (SendcloudApiException $e) {
$ret->Errors[] = $e->getMessage();
}
return $ret;
}
public function GetShippingProducts(): array
{
$this->FetchOptionsFromApi(); $this->FetchOptionsFromApi();
/** @var ShippingProduct $product */ /** @var ShippingProduct $product */
$product = $this->options['selectedProduct']; $product = $this->options['selectedProduct'];
$methods = []; $result = [];
/** @var ShippingMethod $item */ /** @var ShippingMethod $item */
foreach ($product->ShippingMethods as $item) foreach ($product->ShippingMethods as $item) {
$methods[$item->Id] = $item->Name; $p = new Product();
$address['method'] = array_key_first($methods); $p->Id = $item->Id;
$address['sendungsart'] = $this->settings->default_customs_shipment_type; $p->Name = $item->Name;
$result[] = $p;
$this->app->Tpl->Set('JSON', json_encode($address)); }
$this->app->Tpl->Set('JSON_COUNTRIES', json_encode($this->app->erp->GetSelectLaenderliste())); return $result;
$this->app->Tpl->Set('JSON_METHODS', json_encode($methods));
$this->app->Tpl->Set('JSON_CUSTOMS_SHIPMENT_TYPES', json_encode($this->options['customs_shipment_types']));
$this->app->Tpl->Parse($target, 'versandarten_sendcloud.tpl');
} }
} }

View File

@ -66,7 +66,6 @@ function xentral_autoloader($class) {
'ICS'=>__DIR__.'/www/plugins/class.ics.php', 'ICS'=>__DIR__.'/www/plugins/class.ics.php',
'USTID'=>__DIR__.'/www/lib/class.ustid.php', 'USTID'=>__DIR__.'/www/lib/class.ustid.php',
'phpprint'=>__DIR__.'/www/plugins/php-print.php', 'phpprint'=>__DIR__.'/www/plugins/php-print.php',
'DHLBusinessShipment'=>__DIR__.'/www/lib/class.intraship.php',
'Navigation'=>__DIR__.'/www/lib/class.navigation_edit.php', 'Navigation'=>__DIR__.'/www/lib/class.navigation_edit.php',
'GoShipment'=>__DIR__.'/www/lib/class.go.php', 'GoShipment'=>__DIR__.'/www/lib/class.go.php',
'UPSShipment'=>__DIR__.'/www/lib/class.ups.php', 'UPSShipment'=>__DIR__.'/www/lib/class.ups.php',