<?php declare(strict_types=1);
namespace ShpclShipcloudConnector;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Exception;
use Shopware\Core\Checkout\Order\OrderDefinition;
use Shopware\Core\Content\ImportExport\Exception\FileNotFoundException;
use Shopware\Core\Defaults;
use Shopware\Core\Framework\Api\Context\SystemSource;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\Plugin;
use Shopware\Core\Framework\Plugin\Context\InstallContext;
use Shopware\Core\Framework\Plugin\Context\UninstallContext;
use Shopware\Core\Framework\Plugin\Context\UpdateContext;
use Shopware\Core\Content\MailTemplate\Aggregate\MailTemplateType\MailTemplateTypeEntity;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\Uuid\Uuid;
class ShpclShipcloudConnector extends Plugin {
const TEMPLATE_TYPE_TECHNICAL_NAME = 'ship_cloud_url';
const TEMPLATE_TYPE_NAME = 'ShipCloudURL';
public function install(InstallContext $context): void {
/** @var Connection $connection */
$connection = $this->container->get('Doctrine\DBAL\Connection');
try {
$templateTypeData['technicalName'] = self::TEMPLATE_TYPE_TECHNICAL_NAME;
$templateTypeData['availableEntities'] = [
'order' => 'order',
'previousState' => 'state_machine_state',
'newState' => 'state_machine_state',
'salesChannel' => 'sales_channel'
];
$templateTypeData['enName'] = self::TEMPLATE_TYPE_NAME . "_EN";
$templateTypeData['deName'] = self::TEMPLATE_TYPE_NAME. "_DE";
$mailTemplateTypeId = $this->createMailTemplateType($connection, $templateTypeData);
$templateData['en-GB']['senderName'] = '{{ salesChannel.name }}';
$templateData['en-GB']['subject'] = 'Return label for your order';
$templateData['en-GB']['description'] = '';
$templateData['en-GB']['contentHtml'] = $this->getMailContent('en-GB', 'url', 'html');
$templateData['en-GB']['contentPlain'] = $this->getMailContent('en-GB', 'url', 'plain');
$templateData['de-DE']['senderName'] = '{{ salesChannel.name }}';
$templateData['de-DE']['subject'] = 'Rücksendeetikett für Ihre Bestellung';
$templateData['de-DE']['description'] = '';
$templateData['de-DE']['contentHtml'] = $this->getMailContent('de-DE', 'url', 'html');
$templateData['de-DE']['contentPlain'] = $this->getMailContent('de-DE', 'url', 'plain');
$this->createMailTemplate($connection, $mailTemplateTypeId, $templateData);
} catch (\Exception $e) {
}
}
public function uninstall(UninstallContext $uninstallContext): void {
//Keep UserData? Then do nothing here
if ($uninstallContext->keepUserData()) {
return;
}
try {
$this->deleteMailTemplate($uninstallContext->getContext(), self::TEMPLATE_TYPE_TECHNICAL_NAME);
} catch (\Exception $e) {
}
/** @var Connection $connection */
try {
$connection = $this->container->get(Connection::class);
$connection->exec('DROP TABLE s_shpcl_shipcloud_carriers');
$connection->exec('DROP TABLE s_shpcl_shipcloud_labels');
$connection->exec('DROP TABLE s_shpcl_shipcloud_tracker');
$connection->exec('DROP TABLE s_shpcl_shipping_attribute');
$connection->exec('Delete FROM system_config where configuration_key LIKE "%ShpclShipcloudConnector.config.%"');
$connection->exec('Delete FROM migration where class LIKE "%s_shpcl_shipcloud_carriers%"');
$connection->exec('Delete FROM migration where class LIKE "%s_shpcl_shipcloud_labels%"');
$connection->exec('Delete FROM migration where class LIKE "%s_shpcl_shipcloud_tracker%"');
$connection->exec('Delete FROM migration where class LIKE "%s_shpcl_shipping_attribute%"');
} catch (Exception $e) {
}
}
/**
* @param Connection $connection
* @param array $data
*
* @return string
*
* @throws DBALException
* @throws InconsistentCriteriaIdsException
* @throws InvalidUuidException
*/
private function createMailTemplateType(Connection $connection, array $data): string {
$mailTemplateTypeId = Uuid::randomHex();
$connection->insert('mail_template_type', [
'id' => Uuid::fromHexToBytes($mailTemplateTypeId),
'technical_name' => $data['technicalName'],
'available_entities' => json_encode($data['availableEntities']),
'created_at' => (new \DateTime())->format(Defaults::STORAGE_DATE_TIME_FORMAT)
]);
$connection->insert('mail_template_type_translation', [
'mail_template_type_id' => Uuid::fromHexToBytes($mailTemplateTypeId),
'language_id' => Uuid::fromHexToBytes($this->getLanguageIdByLocale('en-GB')),
'name' => $data['enName'],
'created_at' => (new \DateTime())->format(Defaults::STORAGE_DATE_TIME_FORMAT)
]);
$connection->insert('mail_template_type_translation', [
'mail_template_type_id' => Uuid::fromHexToBytes($mailTemplateTypeId),
'language_id' => Uuid::fromHexToBytes($this->getLanguageIdByLocale('de-DE')),
'name' => $data['deName'],
'created_at' => (new \DateTime())->format(Defaults::STORAGE_DATE_TIME_FORMAT)
]);
return $mailTemplateTypeId;
}
/**
* @param Connection $connection
* @param string $mailTemplateTypeId
* @param array $data
*
* @return void
*
* @throws Exception
*/
private function createMailTemplate(Connection $connection, string $mailTemplateTypeId, array $data): void {
$mailTemplateId = Uuid::randomHex();
$connection->insert('mail_template', [
'id' => Uuid::fromHexToBytes($mailTemplateId),
'mail_template_type_id' => Uuid::fromHexToBytes($mailTemplateTypeId),
'system_default' => true,
'created_at' => (new \DateTime())->format(Defaults::STORAGE_DATE_TIME_FORMAT)
]);
$connection->insert('mail_template_translation', [
'mail_template_id' => Uuid::fromHexToBytes($mailTemplateId),
'language_id' => Uuid::fromHexToBytes($this->getLanguageIdByLocale('en-GB')),
'sender_name' => $data['en-GB']['senderName'],
'subject' => $data['en-GB']['subject'],
'description' => $data['en-GB']['description'],
'content_html' => $data['en-GB']['contentHtml'],
'content_plain' => $data['en-GB']['contentPlain'],
'created_at' => (new \DateTime())->format(Defaults::STORAGE_DATE_TIME_FORMAT)
]);
$connection->insert('mail_template_translation', [
'mail_template_id' => Uuid::fromHexToBytes($mailTemplateId),
'language_id' => Uuid::fromHexToBytes($this->getLanguageIdByLocale('de-DE')),
'sender_name' => $data['de-DE']['senderName'],
'subject' => $data['de-DE']['subject'],
'description' => $data['de-DE']['description'],
'content_html' => $data['de-DE']['contentHtml'],
'content_plain' => $data['de-DE']['contentPlain'],
'created_at' => (new \DateTime())->format(Defaults::STORAGE_DATE_TIME_FORMAT)
]);
}
/**
* @param string $locale
*
* @return string
*
* @throws InconsistentCriteriaIdsException
*/
private function getLanguageIdByLocale(string $locale): string {
$context = new Context(new SystemSource());
/** @var EntityRepository $languageRepository */
$languageRepository = $this->container->get('language.repository');
$criteria = new Criteria();
$criteria->addAssociation('locale');
$criteria->addFilter(new EqualsFilter('locale.code', $locale));
/** @var LanguageEntity $languageEntity */
$languageEntity = $languageRepository->search($criteria, $context)->first();
return $languageEntity->getId();
}
/**
* @param string $locale
* @param string $prefix
* @param string $type
*
* @return string
*/
private function getMailContent(string $locale, string $prefix, string $type): string {
$path = $this->getPath() . '/Resources/email/' . $locale . '/';
switch ($type) {
case 'html':
$ext = 'html';
break;
case 'plain':
$ext = 'txt';
break;
default:
$ext = 'txt';
}
$file = $path . $prefix . '-' . $type . '.' . $ext;
if (!is_file($file)) {
throw new FileNotFoundException($file);
}
return file_get_contents($file);
}
/**
* @param string $mailTemplateId
*
* @throws DBALException
*/
private function deleteMailTemplateFromSalesChannels(string $mailTemplateId): void {
/** @var Connection $connection */
$connection = $this->container->get('Doctrine\DBAL\Connection');
$connection->executeQuery('DELETE FROM `mail_template_sales_channel` WHERE `mail_template_id` = :id', ['id' => $mailTemplateId]);
}
/**
* @param Context $context
* @param string $technicalName
*
* @throws InconsistentCriteriaIdsException
* @throws DBALException
*/
private function deleteMailTemplate(Context $context, string $technicalName): void {
$mailTemplateTypeId = $this->getMailTemplateTypeId($context, $technicalName);
$mailTemplateId = $this->getMailTemplateId($context, $mailTemplateTypeId);
$this->deleteMailTemplateFromSalesChannels($mailTemplateId);
/** @var EntityRepository $mailTemplateRepository */
$mailTemplateRepository = $this->container->get('mail_template.repository');
$mailTemplateRepository->delete([
[
'id' => $mailTemplateId
]
], $context);
}
/**
* @param Context $context
* @param string $mailTemplateTypeId
*
* @return string
*
*/
private function getMailTemplateId(Context $context, string $mailTemplateTypeId): string {
/** @var EntityRepository $mailTemplateRepository */
$mailTemplateRepository = $this->container->get('mail_template.repository');
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('mailTemplateTypeId', $mailTemplateTypeId));
/** @var MailTemplateEntity $mailTemplateEntity */
$mailTemplateEntity = $mailTemplateRepository->search($criteria, $context)->first();
return $mailTemplateEntity->getId();
}
/**
* @param Context $context
* @param string $technicalName
*
* @throws InconsistentCriteriaIdsException
*/
private function deleteMailTemplateType(Context $context, string $technicalName): void {
$mailTemplateTypeId = $this->getMailTemplateTypeId($context, $technicalName);
/** @var EntityRepository $mailTemplateTypeRepository */
$mailTemplateTypeRepository = $this->container->get('mail_template_type.repository');
$mailTemplateTypeRepository->delete([
[
'id' => $mailTemplateTypeId
]
], $context);
}
/**
* @param Context $context
* @param string $technicalName
*
* @return string
*
*/
private function getMailTemplateTypeId(Context $context, string $technicalName): string {
/** @var EntityRepository $mailTemplateTypeRepository */
$mailTemplateTypeRepository = $this->container->get('mail_template_type.repository');
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('technicalName', $technicalName));
/** @var MailTemplateTypeEntity $mailTemplateTypeEntity */
$mailTemplateTypeEntity = $mailTemplateTypeRepository->search($criteria, $context)->first();
if ($mailTemplateTypeEntity !== null) return $mailTemplateTypeEntity->getId(); else
return "";
}
/**
* @param UpdateContext $updateContext
*/
public function update(UpdateContext $updateContext): void {
}
/**
* @param InstallContext $installContext
*/
public function postInstall(InstallContext $installContext): void {
$this->upsertExportInformationCustomFields();
}
/**
* @param UpdateContext $updateContext
*/
public function postUpdate(UpdateContext $updateContext): void {
$this->upsertExportInformationCustomFields();
}
/**
* Custom fields
*/
private function upsertExportInformationCustomFields(): void {
$db = $this->container->get(Connection::class);
$technicalName = 'shpcl_shipcloud';
$config = [
'label' => [
'en-GB' => 'Shipment status',
'de-DE' => 'Sendungsstatus',
],
'translated' => true,
];
$fields = [
[
'name' => 'shpcl_hook_status',
'type' => \Shopware\Core\System\CustomField\CustomFieldTypes::SELECT,
'config' => [
'label' => [
'de-DE' => 'Sendungsstatus',
'en-GB' => 'Shipment status',
],
'options' => [
[
'value' => 'shipment.tracking.label_created',
'label' => [
'de-DE' => 'Versandmarke erstellt',
'en-GB' => 'Label created',
]
],
[
'value' => 'shipment.tracking.picked_up',
'label' => [
'de-DE' => 'Paket abgeholt',
'en-GB' => 'Picked Up',
]
],
[
'value' => 'shipment.tracking.transit',
'label' => [
'de-DE' => 'Unterwegs',
'en-GB' => 'Transit',
]
],
[
'value' => 'shipment.tracking.out_for_delivery',
'label' => [
'de-DE' => 'Bereit zur Auslieferung',
'en-GB' => 'Out for Delivery',
]
],
[
'value' => 'shipment.tracking.delivered',
'label' => [
'de-DE' => 'Ausgeliefert',
'en-GB' => 'Delivered',
]
],
[
'value' => 'shipment.tracking.awaits_pickup_by_receiver',
'label' => [
'de-DE' => 'Wartet auf Abholung durch Empfänger',
'en-GB' => 'Awaits pickup by receiver',
]
],
[
'value' => 'shipment.tracking.canceled',
'label' => [
'de-DE' => 'Abgebrochen',
'en-GB' => 'Canceled',
]
],
[
'value' => 'shipment.tracking.delayed',
'label' => [
'de-DE' => 'Verspäted',
'en-GB' => 'Delayed',
]
],
[
'value' => 'shipment.tracking.exception',
'label' => [
'de-DE' => 'Fehler',
'en-GB' => 'Exception',
]
],
[
'value' => 'shipment.tracking.not_delivered',
'label' => [
'de-DE' => 'Nicht ausgeliefert',
'en-GB' => 'Not Delivered',
]
],
[
'value' => 'shipment.tracking.notification',
'label' => [
'de-DE' => 'Hinweis',
'en-GB' => 'Notification',
]
],
[
'value' => 'shipment.tracking.unknown',
'label' => [
'de-DE' => 'Unbekannt',
'en-GB' => 'Unknown',
]
],
[
'value' => 'shipment.tracking.multi',
'label' => [
'de-DE' => 'Mehrere Sendungen (Status uneindeutig)',
'en-GB' => 'Multi sates - not clear',
]
],
],
'componentName' => 'sw-single-select',
'customFieldType' => 'select',
'customFieldPosition' => 0,
],
]
];
$db->executeUpdate('INSERT IGNORE INTO `custom_field_set`
(id, name, config, active, created_at)
VALUES
(:id, :name, :config, 1, NOW(3))
ON DUPLICATE KEY UPDATE
`config` = VALUES(`config`),
`updated_at` = NOW(3)', [
'id' => md5($technicalName),
// Workaround to avoid duplicates, see method createDefaultConfiguration()
'name' => $technicalName,
'config' => json_encode($config),
]);
$setId = $db->fetchColumn('SELECT `id` FROM `custom_field_set` WHERE `name` = :name', [
'name' => $technicalName,
]);
foreach ($fields as $field) {
$field['id'] = Uuid::randomBytes();
$field['setId'] = $setId;
$field['config'] = json_encode($field['config']);
$db->executeUpdate('INSERT IGNORE INTO `custom_field`
(id, name, type, config, active, set_id, created_at)
VALUES
(:id, :name, :type, :config, 1, :setId, NOW(3))
ON DUPLICATE KEY UPDATE
`config` = VALUES(`config`),
`type` = VALUES(`type`),
`updated_at` = NOW(3)', $field);
}
$db->executeUpdate('INSERT INTO custom_field_set_relation
(id, set_id, entity_name, created_at)
VALUES
(:id, :setId, :entityName, NOW(3))
ON DUPLICATE KEY UPDATE
`updated_at` = NOW(3)', [
'id' => Uuid::randomBytes(),
'setId' => $setId,
'entityName' => OrderDefinition::ENTITY_NAME,
]);
}
}