From 4f487fa9d2eeb5257699235a5a87e64e4176f964 Mon Sep 17 00:00:00 2001 From: vendidero Date: Mon, 19 Sep 2022 16:10:48 +0200 Subject: [PATCH] Adding /packages directory to release --- none | 9 + package-lock.json | 2 +- .../assets/css/admin.css | 282 ++ .../assets/css/admin.min.css | 1 + .../assets/css/admin.scss | 427 ++ .../assets/js/admin.js | 104 + .../assets/js/admin.min.js | 1 + .../i18n/languages/oss-woocommerce-de_DE.mo | Bin 0 -> 12792 bytes .../i18n/languages/oss-woocommerce-de_DE.po | 787 ++++ .../languages/oss-woocommerce-de_DE_formal.mo | Bin 0 -> 12859 bytes .../languages/oss-woocommerce-de_DE_formal.po | 788 ++++ .../i18n/languages/oss-woocommerce.pot | 673 ++++ .../woocommerce-eu-tax-helper/src/Helper.php | 911 +++++ .../one-stop-shop-woocommerce/license.txt | 699 ++++ .../one-stop-shop-woocommerce.php | 77 + packages/one-stop-shop-woocommerce/readme.txt | 155 + .../one-stop-shop-woocommerce/src/Admin.php | 838 ++++ .../src/AdminNote.php | 92 + .../src/AsyncReportGenerator.php | 301 ++ .../src/CSVExporter.php | 119 + .../src/CSVExporterBOP.php | 125 + .../DeliveryThresholdEmailNotification.php | 113 + .../src/DeliveryThresholdWarning.php | 40 + .../one-stop-shop-woocommerce/src/Install.php | 41 + .../one-stop-shop-woocommerce/src/Package.php | 743 ++++ .../one-stop-shop-woocommerce/src/Queue.php | 514 +++ .../one-stop-shop-woocommerce/src/Report.php | 330 ++ .../src/ReportTable.php | 520 +++ .../src/Settings.php | 203 + .../src/SettingsPage.php | 59 + .../one-stop-shop-woocommerce/src/Tax.php | 528 +++ .../emails/admin-delivery-threshold.php | 42 + .../emails/plain/admin-delivery-threshold.php | 33 + .../one-stop-shop-woocommerce/wpml-config.xml | 5 + .../woocommerce-eu-tax-helper/src/Helper.php | 911 +++++ .../assets/css/admin.css | 48 + .../assets/css/admin.min.css | 1 + .../assets/css/admin.scss | 76 + .../assets/css/parcel-finder.css | 155 + .../assets/css/parcel-finder.min.css | 1 + .../assets/css/parcel-finder.scss | 218 + .../assets/css/preferred-services.css | 156 + .../assets/css/preferred-services.min.css | 1 + .../assets/css/preferred-services.scss | 230 ++ .../assets/img/dhl-official.png | Bin 0 -> 41839 bytes .../assets/img/packstation.png | Bin 0 -> 6273 bytes .../assets/img/parcelshop.png | Bin 0 -> 5538 bytes .../assets/img/post_office.png | Bin 0 -> 4151 bytes .../assets/img/wp-int-eu-preview.png | Bin 0 -> 23720 bytes .../assets/img/wp-int-preview.png | Bin 0 -> 49144 bytes .../assets/js/admin-deutsche-post-label.js | 110 + .../js/admin-deutsche-post-label.min.js | 1 + .../assets/js/admin-internetmarke.js | 266 ++ .../assets/js/admin-internetmarke.min.js | 1 + .../assets/js/parcel-finder.js | 300 ++ .../assets/js/parcel-finder.min.js | 1 + .../assets/js/parcel-locator.js | 420 ++ .../assets/js/parcel-locator.min.js | 1 + .../assets/js/preferred-services.js | 78 + .../assets/js/preferred-services.min.js | 1 + ...undenversand-api-3.2.0-schema-bcs_base.xsd | 3573 +++++++++++++++++ ...undenversand-api-3.2.0-schema-cis_base.xsd | 1122 ++++++ .../geschaeftskundenversand-api-3.2.0.wsdl | 340 ++ .../assets/wsdl/standortsuche-api-1.1.wsdl | 260 ++ .../i18n/holidays.php | 57 + .../woocommerce-germanized-dhl/i18n/iso.php | 260 ++ .../includes/wc-gzd-dhl-core-functions.php | 903 +++++ .../includes/wc-gzd-dhl-legacy-functions.php | 342 ++ .../woocommerce-germanized-dhl/license.txt | 699 ++++ .../src/Admin/Admin.php | 337 ++ .../src/Admin/Importer/DHL.php | 193 + .../src/Admin/Importer/Internetmarke.php | 54 + .../src/Admin/Status.php | 101 + .../woocommerce-germanized-dhl/src/Ajax.php | 98 + .../src/Api/AuthSoap.php | 66 + .../src/Api/FinderSoap.php | 200 + .../src/Api/ImPartnerInformation.php | 31 + .../src/Api/ImProductList.php | 505 +++ .../src/Api/ImProductsSoap.php | 40 + .../src/Api/ImRefundSoap.php | 99 + .../src/Api/ImWarenpostIntRest.php | 388 ++ .../src/Api/Internetmarke.php | 855 ++++ .../src/Api/LabelSoap.php | 812 ++++ .../src/Api/Paket.php | 299 ++ .../src/Api/ParcelRest.php | 53 + .../src/Api/Rest.php | 194 + .../src/Api/ReturnRest.php | 179 + .../src/Api/Soap.php | 88 + .../src/Install.php | 286 ++ .../src/Label/DHL.php | 404 ++ .../src/Label/DHLInlayReturn.php | 15 + .../src/Label/DHLReturn.php | 91 + .../src/Label/DeutschePost.php | 223 + .../src/Label/DeutschePostReturn.php | 38 + .../src/Label/Label.php | 173 + .../src/Label/ReturnLabel.php | 88 + .../src/Legacy/DataStores/Label.php | 574 +++ .../src/Legacy/DownloadHandler.php | 82 + .../src/Legacy/LabelFactory.php | 29 + .../src/Legacy/LabelQuery.php | 475 +++ .../woocommerce-germanized-dhl/src/Order.php | 386 ++ .../src/Package.php | 1107 +++++ .../src/ParcelLocator.php | 1190 ++++++ .../src/ParcelServices.php | 435 ++ .../src/Product.php | 7 + .../src/ShippingProvider/DHL.php | 1958 +++++++++ .../src/ShippingProvider/DeutschePost.php | 746 ++++ .../src/ShippingProvider/ShippingMethod.php | 101 + .../checkout/dhl/parcel-finder-result.php | 47 + .../templates/checkout/dhl/parcel-finder.php | 68 + .../checkout/dhl/preferred-services.php | 107 + .../woocommerce-germanized-dhl.php | 72 + .../assets/css/admin.css | 888 ++++ .../assets/css/admin.min.css | 1 + .../assets/css/admin.scss | 1383 +++++++ .../js/admin-shipment-label-backbone.js | 295 ++ .../js/admin-shipment-label-backbone.min.js | 1 + .../assets/js/admin-shipment.js | 525 +++ .../assets/js/admin-shipment.min.js | 1 + .../assets/js/admin-shipments-table.js | 178 + .../assets/js/admin-shipments-table.min.js | 1 + .../assets/js/admin-shipments.js | 738 ++++ .../assets/js/admin-shipments.min.js | 1 + .../js/admin-shipping-provider-method.js | 85 + .../js/admin-shipping-provider-method.min.js | 1 + .../assets/js/admin-shipping-providers.js | 177 + .../assets/js/admin-shipping-providers.min.js | 1 + .../html-order-add-return-shipment-items.php | 18 + .../views/html-order-shipment-content.php | 261 ++ .../views/html-order-shipment-item-count.php | 19 + .../admin/views/html-order-shipment-item.php | 69 + .../admin/views/html-order-shipment-list.php | 36 + .../html-order-shipment-packaging-select.php | 35 + .../admin/views/html-order-shipment.php | 31 + .../admin/views/html-order-shipments.php | 94 + .../views/html-settings-provider-list.php | 68 + .../html-shipment-label-backbone-error.php | 22 + .../html-shipment-label-backbone-form.php | 17 + .../label/html-shipment-label-backbone.php | 34 + .../admin/views/label/html-shipment-label.php | 49 + ...customer-guest-return-shipment-request.php | 214 + ...ail-customer-return-shipment-delivered.php | 234 ++ ...-wc-gzd-email-customer-return-shipment.php | 267 ++ .../class-wc-gzd-email-customer-shipment.php | 415 ++ ...-gzd-email-new-return-shipment-request.php | 221 + .../includes/wc-gzd-label-functions.php | 152 + .../includes/wc-gzd-packaging-functions.php | 60 + .../includes/wc-gzd-shipment-functions.php | 1463 +++++++ .../wc-gzd-shipment-template-hooks.php | 28 + .../wc-gzd-shipments-template-functions.php | 204 + .../license.txt | 699 ++++ .../src/AddressSplitter.php | 272 ++ .../src/Admin/Admin.php | 1138 ++++++ .../src/Admin/BulkActionHandler.php | 163 + .../src/Admin/BulkLabel.php | 199 + .../src/Admin/MetaBox.php | 172 + .../src/Admin/ProviderSettings.php | 260 ++ .../src/Admin/ReturnTable.php | 101 + .../src/Admin/Settings.php | 610 +++ .../src/Admin/Table.php | 1168 ++++++ .../src/Ajax.php | 1476 +++++++ .../src/Api.php | 215 + .../src/Automation.php | 247 ++ .../src/DataStores/Label.php | 557 +++ .../src/DataStores/Packaging.php | 694 ++++ .../src/DataStores/Shipment.php | 720 ++++ .../src/DataStores/ShipmentItem.php | 354 ++ .../src/DataStores/ShippingProvider.php | 478 +++ .../src/Emails.php | 232 ++ .../src/FormHandler.php | 325 ++ .../src/Install.php | 322 ++ .../src/Interfaces/ShipmentLabel.php | 97 + .../src/Interfaces/ShipmentReturnLabel.php | 19 + .../src/Interfaces/ShippingProvider.php | 104 + .../src/Interfaces/ShippingProviderAuto.php | 47 + .../src/Labels/Automation.php | 126 + .../src/Labels/DownloadHandler.php | 133 + .../src/Labels/Factory.php | 91 + .../src/Labels/Label.php | 858 ++++ .../src/Labels/Query.php | 490 +++ .../src/Labels/ReturnLabel.php | 119 + .../src/Order.php | 1007 +++++ .../src/PDFMerger.php | 142 + .../src/PDFSplitter.php | 177 + .../src/Package.php | 705 ++++ .../src/Packaging.php | 339 ++ .../src/Packaging/AsyncReportGenerator.php | 164 + .../src/Packaging/Report.php | 310 ++ .../src/Packaging/ReportHelper.php | 487 +++ .../src/Packaging/ReportQueue.php | 337 ++ .../src/PackagingFactory.php | 65 + .../src/Packing/Helper.php | 31 + .../src/Packing/OrderItem.php | 117 + .../src/Packing/PackagingBox.php | 147 + .../src/Packing/ShipmentItem.php | 111 + .../src/Product.php | 130 + .../src/Rest/ShipmentsController.php | 2053 ++++++++++ .../src/ReturnReason.php | 46 + .../src/ReturnShipment.php | 478 +++ .../src/Shipment.php | 2770 +++++++++++++ .../src/ShipmentFactory.php | 88 + .../src/ShipmentItem.php | 605 +++ .../src/ShipmentQuery.php | 540 +++ .../src/ShipmentReturnItem.php | 32 + .../src/ShippingProvider/Auto.php | 562 +++ .../src/ShippingProvider/Helper.php | 202 + .../src/ShippingProvider/Method.php | 414 ++ .../ShippingProvider/MethodPlaceholder.php | 25 + .../src/ShippingProvider/Simple.php | 1187 ++++++ .../src/SimpleShipment.php | 384 ++ .../src/Validation.php | 234 ++ .../src/WPMLHelper.php | 142 + .../admin-new-return-shipment-request.php | 60 + ...customer-guest-return-shipment-request.php | 50 + .../customer-return-shipment-delivered.php | 61 + .../emails/customer-return-shipment.php | 67 + .../templates/emails/customer-shipment.php | 69 + .../emails/email-order-shipments.php | 53 + .../email-return-shipment-instructions.php | 26 + .../emails/email-shipment-address.php | 34 + .../emails/email-shipment-details.php | 87 + .../templates/emails/email-shipment-items.php | 114 + .../emails/email-shipment-tracking.php | 42 + .../admin-new-return-shipment-request.php | 41 + ...customer-guest-return-shipment-request.php | 40 + .../customer-return-shipment-delivered.php | 43 + .../emails/plain/customer-return-shipment.php | 48 + .../emails/plain/customer-shipment.php | 49 + .../emails/plain/email-order-shipments.php | 47 + .../email-return-shipment-instructions.php | 23 + .../emails/plain/email-shipment-address.php | 20 + .../emails/plain/email-shipment-details.php | 43 + .../emails/plain/email-shipment-items.php | 46 + .../emails/plain/email-shipment-tracking.php | 33 + .../templates/global/empty.php | 21 + .../templates/global/form-return-request.php | 51 + .../myaccount/add-return-shipment.php | 96 + .../templates/myaccount/order-shipments.php | 53 + .../templates/myaccount/shipments.php | 113 + .../templates/myaccount/view-shipment.php | 42 + .../shipment/add-return-shipment-item.php | 90 + .../shipment/shipment-details-address.php | 52 + .../shipment/shipment-details-item.php | 93 + .../shipment/shipment-details-tracking.php | 44 + .../templates/shipment/shipment-details.php | 123 + .../shipment/shipment-return-instructions.php | 41 + .../woocommerce-germanized-shipments.php | 72 + .../assets/css/activation.css | 22 + .../assets/css/activation.min.css | 1 + .../assets/css/activation.scss | 23 + .../assets/css/admin.css | 153 + .../assets/css/admin.min.css | 1 + .../assets/css/admin.scss | 208 + .../assets/css/layout.css | 19 + .../assets/css/layout.min.css | 1 + .../assets/css/layout.scss | 26 + .../assets/images/ts/trusted-shops-badge.png | Bin 0 -> 20763 bytes .../images/ts/trusted-shops-badge@2x.png | Bin 0 -> 58032 bytes .../assets/images/ts/ts_de.png | Bin 0 -> 67486 bytes .../assets/images/ts/ts_en.png | Bin 0 -> 68806 bytes .../assets/images/ts/ts_fr.png | Bin 0 -> 68640 bytes .../images/ts/ts_product_reviews_de.jpg | Bin 0 -> 80141 bytes .../images/ts/ts_product_reviews_en.jpg | Bin 0 -> 84405 bytes .../images/ts/ts_product_reviews_fr.jpg | Bin 0 -> 73944 bytes .../images/ts/ts_shop_review_sticker_de.jpg | Bin 0 -> 71078 bytes .../images/ts/ts_shop_review_sticker_en.jpg | Bin 0 -> 70150 bytes .../images/ts/ts_shop_review_sticker_fr.jpg | Bin 0 -> 72007 bytes .../ts/ts_trustbadge_trustmark-only_de.png | Bin 0 -> 21913 bytes .../ts/ts_trustbadge_trustmark-only_en.png | Bin 0 -> 22025 bytes .../ts/ts_trustbadge_trustmark-only_fr.png | Bin 0 -> 21903 bytes .../ts/ts_trustbadge_trustmark_reviews_de.png | Bin 0 -> 44263 bytes .../ts/ts_trustbadge_trustmark_reviews_en.png | Bin 0 -> 44454 bytes .../ts/ts_trustbadge_trustmark_reviews_fr.png | Bin 0 -> 44138 bytes .../assets/images/ts/ts_woo_de.jpg | Bin 0 -> 77174 bytes .../assets/images/ts/ts_woo_en.jpg | Bin 0 -> 75591 bytes .../assets/images/ts/ts_woo_fr.jpg | Bin 0 -> 73172 bytes .../assets/js/admin.js | 278 ++ .../assets/js/admin.min.js | 1 + .../woocommerce-trusted-shops-de_DE.mo | Bin 0 -> 25582 bytes .../woocommerce-trusted-shops-de_DE.po | 1166 ++++++ .../woocommerce-trusted-shops-de_DE_formal.mo | Bin 0 -> 25805 bytes .../woocommerce-trusted-shops-de_DE_formal.po | 1172 ++++++ .../woocommerce-trusted-shops-fr_FR.mo | Bin 0 -> 26951 bytes .../woocommerce-trusted-shops-fr_FR.po | 1165 ++++++ .../abstract-wc-ts-compatibility.php | 87 + .../settings/class-wc-ts-gzd-settings-tab.php | 99 + .../admin/views/html-notice-dependencies.php | 58 + .../admin/views/html-notice-update.php | 20 + .../admin/views/html-settings-section.php | 44 + .../includes/admin/views/html-wpml-notice.php | 20 + .../includes/class-wc-trusted-shops-admin.php | 1020 +++++ .../includes/class-wc-trusted-shops-core.php | 471 +++ ...class-wc-trusted-shops-review-exporter.php | 171 + .../class-wc-trusted-shops-schedule.php | 246 ++ .../class-wc-trusted-shops-shortcodes.php | 99 + .../class-wc-trusted-shops-template-hooks.php | 280 ++ .../class-wc-trusted-shops-widgets.php | 34 + .../includes/class-wc-trusted-shops.php | 689 ++++ .../includes/class-wc-ts-dependencies.php | 144 + .../includes/class-wc-ts-install.php | 171 + .../includes/class-wc-ts-settings-handler.php | 77 + ...-compatibility-wpml-string-translation.php | 342 ++ ...ass-wc-ts-email-customer-trusted-shops.php | 165 + .../updates/woocommerce-ts-update-3.0.0.php | 23 + .../updates/woocommerce-ts-update-4.0.6.php | 14 + .../includes/wc-ts-core-functions.php | 333 ++ ...wc-trusted-shops-widget-review-sticker.php | 66 + .../woocommerce-trusted-shops/license.txt | 699 ++++ packages/woocommerce-trusted-shops/readme.txt | 152 + .../woocommerce-trusted-shops/src/Package.php | 113 + .../emails/cancel-review-reminder.php | 16 + .../emails/customer-trusted-shops.php | 37 + .../emails/plain/customer-trusted-shops.php | 34 + .../trusted-shops/product-sticker-tpl.php | 34 + .../trusted-shops/product-sticker.php | 21 + .../trusted-shops/product-widget-tpl.php | 22 + .../trusted-shops/product-widget.php | 25 + .../trusted-shops/review-sticker-tpl.php | 33 + .../trusted-shops/review-sticker.php | 19 + .../trusted-shops/rich-snippets-tpl.php | 22 + .../templates/trusted-shops/rich-snippets.php | 18 + .../templates/trusted-shops/thankyou.php | 57 + .../trusted-shops/trustbadge-tpl.php | 29 + .../templates/trusted-shops/trustbadge.php | 17 + .../woocommerce-trusted-shops.php | 73 + 325 files changed, 80508 insertions(+), 1 deletion(-) create mode 100644 none create mode 100644 packages/one-stop-shop-woocommerce/assets/css/admin.css create mode 100644 packages/one-stop-shop-woocommerce/assets/css/admin.min.css create mode 100644 packages/one-stop-shop-woocommerce/assets/css/admin.scss create mode 100644 packages/one-stop-shop-woocommerce/assets/js/admin.js create mode 100644 packages/one-stop-shop-woocommerce/assets/js/admin.min.js create mode 100644 packages/one-stop-shop-woocommerce/i18n/languages/oss-woocommerce-de_DE.mo create mode 100644 packages/one-stop-shop-woocommerce/i18n/languages/oss-woocommerce-de_DE.po create mode 100644 packages/one-stop-shop-woocommerce/i18n/languages/oss-woocommerce-de_DE_formal.mo create mode 100644 packages/one-stop-shop-woocommerce/i18n/languages/oss-woocommerce-de_DE_formal.po create mode 100644 packages/one-stop-shop-woocommerce/i18n/languages/oss-woocommerce.pot create mode 100644 packages/one-stop-shop-woocommerce/libs/woocommerce-eu-tax-helper/src/Helper.php create mode 100644 packages/one-stop-shop-woocommerce/license.txt create mode 100644 packages/one-stop-shop-woocommerce/one-stop-shop-woocommerce.php create mode 100644 packages/one-stop-shop-woocommerce/readme.txt create mode 100644 packages/one-stop-shop-woocommerce/src/Admin.php create mode 100644 packages/one-stop-shop-woocommerce/src/AdminNote.php create mode 100644 packages/one-stop-shop-woocommerce/src/AsyncReportGenerator.php create mode 100644 packages/one-stop-shop-woocommerce/src/CSVExporter.php create mode 100644 packages/one-stop-shop-woocommerce/src/CSVExporterBOP.php create mode 100644 packages/one-stop-shop-woocommerce/src/DeliveryThresholdEmailNotification.php create mode 100644 packages/one-stop-shop-woocommerce/src/DeliveryThresholdWarning.php create mode 100644 packages/one-stop-shop-woocommerce/src/Install.php create mode 100644 packages/one-stop-shop-woocommerce/src/Package.php create mode 100644 packages/one-stop-shop-woocommerce/src/Queue.php create mode 100644 packages/one-stop-shop-woocommerce/src/Report.php create mode 100644 packages/one-stop-shop-woocommerce/src/ReportTable.php create mode 100644 packages/one-stop-shop-woocommerce/src/Settings.php create mode 100644 packages/one-stop-shop-woocommerce/src/SettingsPage.php create mode 100644 packages/one-stop-shop-woocommerce/src/Tax.php create mode 100644 packages/one-stop-shop-woocommerce/templates/emails/admin-delivery-threshold.php create mode 100644 packages/one-stop-shop-woocommerce/templates/emails/plain/admin-delivery-threshold.php create mode 100644 packages/one-stop-shop-woocommerce/wpml-config.xml create mode 100644 packages/woocommerce-eu-tax-helper/src/Helper.php create mode 100644 packages/woocommerce-germanized-dhl/assets/css/admin.css create mode 100644 packages/woocommerce-germanized-dhl/assets/css/admin.min.css create mode 100644 packages/woocommerce-germanized-dhl/assets/css/admin.scss create mode 100644 packages/woocommerce-germanized-dhl/assets/css/parcel-finder.css create mode 100644 packages/woocommerce-germanized-dhl/assets/css/parcel-finder.min.css create mode 100644 packages/woocommerce-germanized-dhl/assets/css/parcel-finder.scss create mode 100644 packages/woocommerce-germanized-dhl/assets/css/preferred-services.css create mode 100644 packages/woocommerce-germanized-dhl/assets/css/preferred-services.min.css create mode 100644 packages/woocommerce-germanized-dhl/assets/css/preferred-services.scss create mode 100755 packages/woocommerce-germanized-dhl/assets/img/dhl-official.png create mode 100755 packages/woocommerce-germanized-dhl/assets/img/packstation.png create mode 100755 packages/woocommerce-germanized-dhl/assets/img/parcelshop.png create mode 100755 packages/woocommerce-germanized-dhl/assets/img/post_office.png create mode 100644 packages/woocommerce-germanized-dhl/assets/img/wp-int-eu-preview.png create mode 100644 packages/woocommerce-germanized-dhl/assets/img/wp-int-preview.png create mode 100644 packages/woocommerce-germanized-dhl/assets/js/admin-deutsche-post-label.js create mode 100644 packages/woocommerce-germanized-dhl/assets/js/admin-deutsche-post-label.min.js create mode 100644 packages/woocommerce-germanized-dhl/assets/js/admin-internetmarke.js create mode 100644 packages/woocommerce-germanized-dhl/assets/js/admin-internetmarke.min.js create mode 100644 packages/woocommerce-germanized-dhl/assets/js/parcel-finder.js create mode 100644 packages/woocommerce-germanized-dhl/assets/js/parcel-finder.min.js create mode 100644 packages/woocommerce-germanized-dhl/assets/js/parcel-locator.js create mode 100644 packages/woocommerce-germanized-dhl/assets/js/parcel-locator.min.js create mode 100644 packages/woocommerce-germanized-dhl/assets/js/preferred-services.js create mode 100644 packages/woocommerce-germanized-dhl/assets/js/preferred-services.min.js create mode 100644 packages/woocommerce-germanized-dhl/assets/wsdl/geschaeftskundenversand-api-3.2.0-schema-bcs_base.xsd create mode 100644 packages/woocommerce-germanized-dhl/assets/wsdl/geschaeftskundenversand-api-3.2.0-schema-cis_base.xsd create mode 100644 packages/woocommerce-germanized-dhl/assets/wsdl/geschaeftskundenversand-api-3.2.0.wsdl create mode 100644 packages/woocommerce-germanized-dhl/assets/wsdl/standortsuche-api-1.1.wsdl create mode 100644 packages/woocommerce-germanized-dhl/i18n/holidays.php create mode 100644 packages/woocommerce-germanized-dhl/i18n/iso.php create mode 100644 packages/woocommerce-germanized-dhl/includes/wc-gzd-dhl-core-functions.php create mode 100644 packages/woocommerce-germanized-dhl/includes/wc-gzd-dhl-legacy-functions.php create mode 100644 packages/woocommerce-germanized-dhl/license.txt create mode 100644 packages/woocommerce-germanized-dhl/src/Admin/Admin.php create mode 100644 packages/woocommerce-germanized-dhl/src/Admin/Importer/DHL.php create mode 100644 packages/woocommerce-germanized-dhl/src/Admin/Importer/Internetmarke.php create mode 100644 packages/woocommerce-germanized-dhl/src/Admin/Status.php create mode 100644 packages/woocommerce-germanized-dhl/src/Ajax.php create mode 100644 packages/woocommerce-germanized-dhl/src/Api/AuthSoap.php create mode 100644 packages/woocommerce-germanized-dhl/src/Api/FinderSoap.php create mode 100644 packages/woocommerce-germanized-dhl/src/Api/ImPartnerInformation.php create mode 100644 packages/woocommerce-germanized-dhl/src/Api/ImProductList.php create mode 100644 packages/woocommerce-germanized-dhl/src/Api/ImProductsSoap.php create mode 100644 packages/woocommerce-germanized-dhl/src/Api/ImRefundSoap.php create mode 100644 packages/woocommerce-germanized-dhl/src/Api/ImWarenpostIntRest.php create mode 100644 packages/woocommerce-germanized-dhl/src/Api/Internetmarke.php create mode 100644 packages/woocommerce-germanized-dhl/src/Api/LabelSoap.php create mode 100644 packages/woocommerce-germanized-dhl/src/Api/Paket.php create mode 100644 packages/woocommerce-germanized-dhl/src/Api/ParcelRest.php create mode 100644 packages/woocommerce-germanized-dhl/src/Api/Rest.php create mode 100644 packages/woocommerce-germanized-dhl/src/Api/ReturnRest.php create mode 100644 packages/woocommerce-germanized-dhl/src/Api/Soap.php create mode 100644 packages/woocommerce-germanized-dhl/src/Install.php create mode 100644 packages/woocommerce-germanized-dhl/src/Label/DHL.php create mode 100644 packages/woocommerce-germanized-dhl/src/Label/DHLInlayReturn.php create mode 100644 packages/woocommerce-germanized-dhl/src/Label/DHLReturn.php create mode 100644 packages/woocommerce-germanized-dhl/src/Label/DeutschePost.php create mode 100644 packages/woocommerce-germanized-dhl/src/Label/DeutschePostReturn.php create mode 100644 packages/woocommerce-germanized-dhl/src/Label/Label.php create mode 100644 packages/woocommerce-germanized-dhl/src/Label/ReturnLabel.php create mode 100644 packages/woocommerce-germanized-dhl/src/Legacy/DataStores/Label.php create mode 100644 packages/woocommerce-germanized-dhl/src/Legacy/DownloadHandler.php create mode 100644 packages/woocommerce-germanized-dhl/src/Legacy/LabelFactory.php create mode 100644 packages/woocommerce-germanized-dhl/src/Legacy/LabelQuery.php create mode 100644 packages/woocommerce-germanized-dhl/src/Order.php create mode 100644 packages/woocommerce-germanized-dhl/src/Package.php create mode 100644 packages/woocommerce-germanized-dhl/src/ParcelLocator.php create mode 100644 packages/woocommerce-germanized-dhl/src/ParcelServices.php create mode 100644 packages/woocommerce-germanized-dhl/src/Product.php create mode 100644 packages/woocommerce-germanized-dhl/src/ShippingProvider/DHL.php create mode 100644 packages/woocommerce-germanized-dhl/src/ShippingProvider/DeutschePost.php create mode 100644 packages/woocommerce-germanized-dhl/src/ShippingProvider/ShippingMethod.php create mode 100644 packages/woocommerce-germanized-dhl/templates/checkout/dhl/parcel-finder-result.php create mode 100644 packages/woocommerce-germanized-dhl/templates/checkout/dhl/parcel-finder.php create mode 100644 packages/woocommerce-germanized-dhl/templates/checkout/dhl/preferred-services.php create mode 100644 packages/woocommerce-germanized-dhl/woocommerce-germanized-dhl.php create mode 100644 packages/woocommerce-germanized-shipments/assets/css/admin.css create mode 100644 packages/woocommerce-germanized-shipments/assets/css/admin.min.css create mode 100644 packages/woocommerce-germanized-shipments/assets/css/admin.scss create mode 100644 packages/woocommerce-germanized-shipments/assets/js/admin-shipment-label-backbone.js create mode 100644 packages/woocommerce-germanized-shipments/assets/js/admin-shipment-label-backbone.min.js create mode 100644 packages/woocommerce-germanized-shipments/assets/js/admin-shipment.js create mode 100644 packages/woocommerce-germanized-shipments/assets/js/admin-shipment.min.js create mode 100644 packages/woocommerce-germanized-shipments/assets/js/admin-shipments-table.js create mode 100644 packages/woocommerce-germanized-shipments/assets/js/admin-shipments-table.min.js create mode 100644 packages/woocommerce-germanized-shipments/assets/js/admin-shipments.js create mode 100644 packages/woocommerce-germanized-shipments/assets/js/admin-shipments.min.js create mode 100644 packages/woocommerce-germanized-shipments/assets/js/admin-shipping-provider-method.js create mode 100644 packages/woocommerce-germanized-shipments/assets/js/admin-shipping-provider-method.min.js create mode 100644 packages/woocommerce-germanized-shipments/assets/js/admin-shipping-providers.js create mode 100644 packages/woocommerce-germanized-shipments/assets/js/admin-shipping-providers.min.js create mode 100644 packages/woocommerce-germanized-shipments/includes/admin/views/html-order-add-return-shipment-items.php create mode 100644 packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipment-content.php create mode 100644 packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipment-item-count.php create mode 100644 packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipment-item.php create mode 100644 packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipment-list.php create mode 100644 packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipment-packaging-select.php create mode 100644 packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipment.php create mode 100644 packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipments.php create mode 100644 packages/woocommerce-germanized-shipments/includes/admin/views/html-settings-provider-list.php create mode 100644 packages/woocommerce-germanized-shipments/includes/admin/views/label/html-shipment-label-backbone-error.php create mode 100644 packages/woocommerce-germanized-shipments/includes/admin/views/label/html-shipment-label-backbone-form.php create mode 100644 packages/woocommerce-germanized-shipments/includes/admin/views/label/html-shipment-label-backbone.php create mode 100644 packages/woocommerce-germanized-shipments/includes/admin/views/label/html-shipment-label.php create mode 100644 packages/woocommerce-germanized-shipments/includes/emails/class-wc-gzd-email-customer-guest-return-shipment-request.php create mode 100644 packages/woocommerce-germanized-shipments/includes/emails/class-wc-gzd-email-customer-return-shipment-delivered.php create mode 100644 packages/woocommerce-germanized-shipments/includes/emails/class-wc-gzd-email-customer-return-shipment.php create mode 100644 packages/woocommerce-germanized-shipments/includes/emails/class-wc-gzd-email-customer-shipment.php create mode 100644 packages/woocommerce-germanized-shipments/includes/emails/class-wc-gzd-email-new-return-shipment-request.php create mode 100644 packages/woocommerce-germanized-shipments/includes/wc-gzd-label-functions.php create mode 100644 packages/woocommerce-germanized-shipments/includes/wc-gzd-packaging-functions.php create mode 100644 packages/woocommerce-germanized-shipments/includes/wc-gzd-shipment-functions.php create mode 100644 packages/woocommerce-germanized-shipments/includes/wc-gzd-shipment-template-hooks.php create mode 100644 packages/woocommerce-germanized-shipments/includes/wc-gzd-shipments-template-functions.php create mode 100644 packages/woocommerce-germanized-shipments/license.txt create mode 100644 packages/woocommerce-germanized-shipments/src/AddressSplitter.php create mode 100644 packages/woocommerce-germanized-shipments/src/Admin/Admin.php create mode 100644 packages/woocommerce-germanized-shipments/src/Admin/BulkActionHandler.php create mode 100644 packages/woocommerce-germanized-shipments/src/Admin/BulkLabel.php create mode 100644 packages/woocommerce-germanized-shipments/src/Admin/MetaBox.php create mode 100644 packages/woocommerce-germanized-shipments/src/Admin/ProviderSettings.php create mode 100644 packages/woocommerce-germanized-shipments/src/Admin/ReturnTable.php create mode 100644 packages/woocommerce-germanized-shipments/src/Admin/Settings.php create mode 100644 packages/woocommerce-germanized-shipments/src/Admin/Table.php create mode 100644 packages/woocommerce-germanized-shipments/src/Ajax.php create mode 100644 packages/woocommerce-germanized-shipments/src/Api.php create mode 100644 packages/woocommerce-germanized-shipments/src/Automation.php create mode 100644 packages/woocommerce-germanized-shipments/src/DataStores/Label.php create mode 100644 packages/woocommerce-germanized-shipments/src/DataStores/Packaging.php create mode 100644 packages/woocommerce-germanized-shipments/src/DataStores/Shipment.php create mode 100644 packages/woocommerce-germanized-shipments/src/DataStores/ShipmentItem.php create mode 100644 packages/woocommerce-germanized-shipments/src/DataStores/ShippingProvider.php create mode 100644 packages/woocommerce-germanized-shipments/src/Emails.php create mode 100644 packages/woocommerce-germanized-shipments/src/FormHandler.php create mode 100644 packages/woocommerce-germanized-shipments/src/Install.php create mode 100644 packages/woocommerce-germanized-shipments/src/Interfaces/ShipmentLabel.php create mode 100644 packages/woocommerce-germanized-shipments/src/Interfaces/ShipmentReturnLabel.php create mode 100644 packages/woocommerce-germanized-shipments/src/Interfaces/ShippingProvider.php create mode 100644 packages/woocommerce-germanized-shipments/src/Interfaces/ShippingProviderAuto.php create mode 100644 packages/woocommerce-germanized-shipments/src/Labels/Automation.php create mode 100644 packages/woocommerce-germanized-shipments/src/Labels/DownloadHandler.php create mode 100644 packages/woocommerce-germanized-shipments/src/Labels/Factory.php create mode 100644 packages/woocommerce-germanized-shipments/src/Labels/Label.php create mode 100644 packages/woocommerce-germanized-shipments/src/Labels/Query.php create mode 100644 packages/woocommerce-germanized-shipments/src/Labels/ReturnLabel.php create mode 100644 packages/woocommerce-germanized-shipments/src/Order.php create mode 100644 packages/woocommerce-germanized-shipments/src/PDFMerger.php create mode 100644 packages/woocommerce-germanized-shipments/src/PDFSplitter.php create mode 100644 packages/woocommerce-germanized-shipments/src/Package.php create mode 100644 packages/woocommerce-germanized-shipments/src/Packaging.php create mode 100644 packages/woocommerce-germanized-shipments/src/Packaging/AsyncReportGenerator.php create mode 100644 packages/woocommerce-germanized-shipments/src/Packaging/Report.php create mode 100644 packages/woocommerce-germanized-shipments/src/Packaging/ReportHelper.php create mode 100644 packages/woocommerce-germanized-shipments/src/Packaging/ReportQueue.php create mode 100644 packages/woocommerce-germanized-shipments/src/PackagingFactory.php create mode 100644 packages/woocommerce-germanized-shipments/src/Packing/Helper.php create mode 100644 packages/woocommerce-germanized-shipments/src/Packing/OrderItem.php create mode 100644 packages/woocommerce-germanized-shipments/src/Packing/PackagingBox.php create mode 100644 packages/woocommerce-germanized-shipments/src/Packing/ShipmentItem.php create mode 100644 packages/woocommerce-germanized-shipments/src/Product.php create mode 100644 packages/woocommerce-germanized-shipments/src/Rest/ShipmentsController.php create mode 100644 packages/woocommerce-germanized-shipments/src/ReturnReason.php create mode 100644 packages/woocommerce-germanized-shipments/src/ReturnShipment.php create mode 100644 packages/woocommerce-germanized-shipments/src/Shipment.php create mode 100644 packages/woocommerce-germanized-shipments/src/ShipmentFactory.php create mode 100644 packages/woocommerce-germanized-shipments/src/ShipmentItem.php create mode 100644 packages/woocommerce-germanized-shipments/src/ShipmentQuery.php create mode 100644 packages/woocommerce-germanized-shipments/src/ShipmentReturnItem.php create mode 100644 packages/woocommerce-germanized-shipments/src/ShippingProvider/Auto.php create mode 100644 packages/woocommerce-germanized-shipments/src/ShippingProvider/Helper.php create mode 100644 packages/woocommerce-germanized-shipments/src/ShippingProvider/Method.php create mode 100644 packages/woocommerce-germanized-shipments/src/ShippingProvider/MethodPlaceholder.php create mode 100644 packages/woocommerce-germanized-shipments/src/ShippingProvider/Simple.php create mode 100644 packages/woocommerce-germanized-shipments/src/SimpleShipment.php create mode 100644 packages/woocommerce-germanized-shipments/src/Validation.php create mode 100644 packages/woocommerce-germanized-shipments/src/WPMLHelper.php create mode 100644 packages/woocommerce-germanized-shipments/templates/emails/admin-new-return-shipment-request.php create mode 100644 packages/woocommerce-germanized-shipments/templates/emails/customer-guest-return-shipment-request.php create mode 100644 packages/woocommerce-germanized-shipments/templates/emails/customer-return-shipment-delivered.php create mode 100644 packages/woocommerce-germanized-shipments/templates/emails/customer-return-shipment.php create mode 100644 packages/woocommerce-germanized-shipments/templates/emails/customer-shipment.php create mode 100644 packages/woocommerce-germanized-shipments/templates/emails/email-order-shipments.php create mode 100644 packages/woocommerce-germanized-shipments/templates/emails/email-return-shipment-instructions.php create mode 100644 packages/woocommerce-germanized-shipments/templates/emails/email-shipment-address.php create mode 100644 packages/woocommerce-germanized-shipments/templates/emails/email-shipment-details.php create mode 100644 packages/woocommerce-germanized-shipments/templates/emails/email-shipment-items.php create mode 100644 packages/woocommerce-germanized-shipments/templates/emails/email-shipment-tracking.php create mode 100644 packages/woocommerce-germanized-shipments/templates/emails/plain/admin-new-return-shipment-request.php create mode 100644 packages/woocommerce-germanized-shipments/templates/emails/plain/customer-guest-return-shipment-request.php create mode 100644 packages/woocommerce-germanized-shipments/templates/emails/plain/customer-return-shipment-delivered.php create mode 100644 packages/woocommerce-germanized-shipments/templates/emails/plain/customer-return-shipment.php create mode 100644 packages/woocommerce-germanized-shipments/templates/emails/plain/customer-shipment.php create mode 100644 packages/woocommerce-germanized-shipments/templates/emails/plain/email-order-shipments.php create mode 100644 packages/woocommerce-germanized-shipments/templates/emails/plain/email-return-shipment-instructions.php create mode 100644 packages/woocommerce-germanized-shipments/templates/emails/plain/email-shipment-address.php create mode 100644 packages/woocommerce-germanized-shipments/templates/emails/plain/email-shipment-details.php create mode 100644 packages/woocommerce-germanized-shipments/templates/emails/plain/email-shipment-items.php create mode 100644 packages/woocommerce-germanized-shipments/templates/emails/plain/email-shipment-tracking.php create mode 100644 packages/woocommerce-germanized-shipments/templates/global/empty.php create mode 100644 packages/woocommerce-germanized-shipments/templates/global/form-return-request.php create mode 100644 packages/woocommerce-germanized-shipments/templates/myaccount/add-return-shipment.php create mode 100644 packages/woocommerce-germanized-shipments/templates/myaccount/order-shipments.php create mode 100644 packages/woocommerce-germanized-shipments/templates/myaccount/shipments.php create mode 100644 packages/woocommerce-germanized-shipments/templates/myaccount/view-shipment.php create mode 100644 packages/woocommerce-germanized-shipments/templates/shipment/add-return-shipment-item.php create mode 100644 packages/woocommerce-germanized-shipments/templates/shipment/shipment-details-address.php create mode 100644 packages/woocommerce-germanized-shipments/templates/shipment/shipment-details-item.php create mode 100644 packages/woocommerce-germanized-shipments/templates/shipment/shipment-details-tracking.php create mode 100644 packages/woocommerce-germanized-shipments/templates/shipment/shipment-details.php create mode 100644 packages/woocommerce-germanized-shipments/templates/shipment/shipment-return-instructions.php create mode 100644 packages/woocommerce-germanized-shipments/woocommerce-germanized-shipments.php create mode 100644 packages/woocommerce-trusted-shops/assets/css/activation.css create mode 100644 packages/woocommerce-trusted-shops/assets/css/activation.min.css create mode 100644 packages/woocommerce-trusted-shops/assets/css/activation.scss create mode 100644 packages/woocommerce-trusted-shops/assets/css/admin.css create mode 100644 packages/woocommerce-trusted-shops/assets/css/admin.min.css create mode 100644 packages/woocommerce-trusted-shops/assets/css/admin.scss create mode 100644 packages/woocommerce-trusted-shops/assets/css/layout.css create mode 100644 packages/woocommerce-trusted-shops/assets/css/layout.min.css create mode 100644 packages/woocommerce-trusted-shops/assets/css/layout.scss create mode 100755 packages/woocommerce-trusted-shops/assets/images/ts/trusted-shops-badge.png create mode 100755 packages/woocommerce-trusted-shops/assets/images/ts/trusted-shops-badge@2x.png create mode 100755 packages/woocommerce-trusted-shops/assets/images/ts/ts_de.png create mode 100755 packages/woocommerce-trusted-shops/assets/images/ts/ts_en.png create mode 100755 packages/woocommerce-trusted-shops/assets/images/ts/ts_fr.png create mode 100755 packages/woocommerce-trusted-shops/assets/images/ts/ts_product_reviews_de.jpg create mode 100755 packages/woocommerce-trusted-shops/assets/images/ts/ts_product_reviews_en.jpg create mode 100755 packages/woocommerce-trusted-shops/assets/images/ts/ts_product_reviews_fr.jpg create mode 100755 packages/woocommerce-trusted-shops/assets/images/ts/ts_shop_review_sticker_de.jpg create mode 100755 packages/woocommerce-trusted-shops/assets/images/ts/ts_shop_review_sticker_en.jpg create mode 100755 packages/woocommerce-trusted-shops/assets/images/ts/ts_shop_review_sticker_fr.jpg create mode 100644 packages/woocommerce-trusted-shops/assets/images/ts/ts_trustbadge_trustmark-only_de.png create mode 100644 packages/woocommerce-trusted-shops/assets/images/ts/ts_trustbadge_trustmark-only_en.png create mode 100644 packages/woocommerce-trusted-shops/assets/images/ts/ts_trustbadge_trustmark-only_fr.png create mode 100755 packages/woocommerce-trusted-shops/assets/images/ts/ts_trustbadge_trustmark_reviews_de.png create mode 100755 packages/woocommerce-trusted-shops/assets/images/ts/ts_trustbadge_trustmark_reviews_en.png create mode 100755 packages/woocommerce-trusted-shops/assets/images/ts/ts_trustbadge_trustmark_reviews_fr.png create mode 100755 packages/woocommerce-trusted-shops/assets/images/ts/ts_woo_de.jpg create mode 100755 packages/woocommerce-trusted-shops/assets/images/ts/ts_woo_en.jpg create mode 100755 packages/woocommerce-trusted-shops/assets/images/ts/ts_woo_fr.jpg create mode 100644 packages/woocommerce-trusted-shops/assets/js/admin.js create mode 100644 packages/woocommerce-trusted-shops/assets/js/admin.min.js create mode 100644 packages/woocommerce-trusted-shops/i18n/languages/woocommerce-trusted-shops-de_DE.mo create mode 100644 packages/woocommerce-trusted-shops/i18n/languages/woocommerce-trusted-shops-de_DE.po create mode 100644 packages/woocommerce-trusted-shops/i18n/languages/woocommerce-trusted-shops-de_DE_formal.mo create mode 100644 packages/woocommerce-trusted-shops/i18n/languages/woocommerce-trusted-shops-de_DE_formal.po create mode 100644 packages/woocommerce-trusted-shops/i18n/languages/woocommerce-trusted-shops-fr_FR.mo create mode 100644 packages/woocommerce-trusted-shops/i18n/languages/woocommerce-trusted-shops-fr_FR.po create mode 100644 packages/woocommerce-trusted-shops/includes/abstracts/abstract-wc-ts-compatibility.php create mode 100644 packages/woocommerce-trusted-shops/includes/admin/settings/class-wc-ts-gzd-settings-tab.php create mode 100644 packages/woocommerce-trusted-shops/includes/admin/views/html-notice-dependencies.php create mode 100644 packages/woocommerce-trusted-shops/includes/admin/views/html-notice-update.php create mode 100644 packages/woocommerce-trusted-shops/includes/admin/views/html-settings-section.php create mode 100644 packages/woocommerce-trusted-shops/includes/admin/views/html-wpml-notice.php create mode 100644 packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-admin.php create mode 100644 packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-core.php create mode 100644 packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-review-exporter.php create mode 100644 packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-schedule.php create mode 100644 packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-shortcodes.php create mode 100644 packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-template-hooks.php create mode 100644 packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-widgets.php create mode 100644 packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops.php create mode 100644 packages/woocommerce-trusted-shops/includes/class-wc-ts-dependencies.php create mode 100644 packages/woocommerce-trusted-shops/includes/class-wc-ts-install.php create mode 100644 packages/woocommerce-trusted-shops/includes/class-wc-ts-settings-handler.php create mode 100644 packages/woocommerce-trusted-shops/includes/compatibility/class-wc-ts-compatibility-wpml-string-translation.php create mode 100644 packages/woocommerce-trusted-shops/includes/emails/class-wc-ts-email-customer-trusted-shops.php create mode 100644 packages/woocommerce-trusted-shops/includes/updates/woocommerce-ts-update-3.0.0.php create mode 100644 packages/woocommerce-trusted-shops/includes/updates/woocommerce-ts-update-4.0.6.php create mode 100644 packages/woocommerce-trusted-shops/includes/wc-ts-core-functions.php create mode 100644 packages/woocommerce-trusted-shops/includes/widgets/class-wc-trusted-shops-widget-review-sticker.php create mode 100644 packages/woocommerce-trusted-shops/license.txt create mode 100644 packages/woocommerce-trusted-shops/readme.txt create mode 100644 packages/woocommerce-trusted-shops/src/Package.php create mode 100644 packages/woocommerce-trusted-shops/templates/emails/cancel-review-reminder.php create mode 100644 packages/woocommerce-trusted-shops/templates/emails/customer-trusted-shops.php create mode 100644 packages/woocommerce-trusted-shops/templates/emails/plain/customer-trusted-shops.php create mode 100644 packages/woocommerce-trusted-shops/templates/trusted-shops/product-sticker-tpl.php create mode 100644 packages/woocommerce-trusted-shops/templates/trusted-shops/product-sticker.php create mode 100644 packages/woocommerce-trusted-shops/templates/trusted-shops/product-widget-tpl.php create mode 100644 packages/woocommerce-trusted-shops/templates/trusted-shops/product-widget.php create mode 100644 packages/woocommerce-trusted-shops/templates/trusted-shops/review-sticker-tpl.php create mode 100644 packages/woocommerce-trusted-shops/templates/trusted-shops/review-sticker.php create mode 100644 packages/woocommerce-trusted-shops/templates/trusted-shops/rich-snippets-tpl.php create mode 100644 packages/woocommerce-trusted-shops/templates/trusted-shops/rich-snippets.php create mode 100644 packages/woocommerce-trusted-shops/templates/trusted-shops/thankyou.php create mode 100644 packages/woocommerce-trusted-shops/templates/trusted-shops/trustbadge-tpl.php create mode 100644 packages/woocommerce-trusted-shops/templates/trusted-shops/trustbadge.php create mode 100644 packages/woocommerce-trusted-shops/woocommerce-trusted-shops.php diff --git a/none b/none new file mode 100644 index 000000000..4a0376d3b --- /dev/null +++ b/none @@ -0,0 +1,9 @@ +{ + "version": 3, + "file": "assets/css/layout.css", + "sources": [ + "assets/css/layout.scss" + ], + "names": [], + "mappings": "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" +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index be73728ad..a9cc87d01 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "woocommerce-germanized", - "version": "3.9.2", + "version": "3.10.6", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/packages/one-stop-shop-woocommerce/assets/css/admin.css b/packages/one-stop-shop-woocommerce/assets/css/admin.css new file mode 100644 index 000000000..e347a856e --- /dev/null +++ b/packages/one-stop-shop-woocommerce/assets/css/admin.css @@ -0,0 +1,282 @@ +p.oss-woocommerce-additional-desc { + margin-top: 1em !important; + line-height: 1.5em; + background: #fff; + padding: .5em; + font-style: normal; + font-size: 14px; + box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1); } + +h2.oss-woocommerce-settings-title { + margin-top: 1.5em; } + h2.oss-woocommerce-settings-title .page-title-action { + top: 0; } + +.oss-add-tax-class-by-country-template { + display: none; } + +a.oss-remove-tax-class-by-country { + text-indent: 0; + overflow: hidden; + color: #b32d2e; + text-decoration: none; + vertical-align: middle; } + +p.oss-tax-class-by-country-field { + display: flex; + flex-wrap: wrap; + align-items: center; } + p.oss-tax-class-by-country-field label { + width: 100%; } + p.oss-tax-class-by-country-field select { + width: auto; + flex-grow: 1; + flex-shrink: 0; + flex-basis: 50%; } + p.oss-tax-class-by-country-field a.oss-remove-tax-class-by-country { + margin-left: .5em; } + +p.oss-add-tax-class-by-country-field { + display: flex; + align-items: center; + width: 100%; } + p.oss-add-tax-class-by-country-field a.oss-remove-tax-class-by-country { + margin-left: .5em; } + p.oss-add-tax-class-by-country-field label { + width: auto; + flex-grow: 0; + flex-shrink: 0; + flex-basis: 30%; + margin-right: 1em; } + p.oss-add-tax-class-by-country-field select.oss-tax-class-new-class { + width: auto; + flex-grow: 1; + flex-shrink: 0; + flex-basis: 50%; } + +.oss-observer-total { + font-size: 1.5em; + background: #b1dabc; + color: #1d4026; + padding: 3px; + border-radius: 2px; } + .oss-observer-total.observer-total-red { + background: #dab1b4; + color: #401d1d; } + +.oss-settings-learn-more, .oss-settings-refresh-tax-rates { + margin-left: .5em; } + +.oss-observer-date-end { + color: #646970; + font-size: 12px; + margin-left: .5em; } + +.oss-woo-status { + background: #eee; + padding: .2em .5em; + font-size: .9em; + border-radius: 3px; + display: inline-flex; + white-space: nowrap; } + .oss-woo-status.report-status-pending { + background: #f8dda7; + color: #94660c; } + .oss-woo-status.report-status-failed { + background: #eba3a3; + color: #761919; } + .oss-woo-status.report-status-completed { + background: #c6e1c6; + color: #5b841b; } + +.create-oss-reports { + text-align: center; + max-width: 700px; + margin: 40px auto; } + .create-oss-reports .create-oss-report { + background: #fff; + overflow: hidden; + padding: 0; + margin: 0 0 16px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.13); + color: #555; + text-align: left; } + .create-oss-reports header { + border-bottom: 1px solid #eee; + margin: 0; + padding: 24px 24px 0; } + .create-oss-reports header h2 { + margin: 0 0 24px; + color: #555; + font-size: 24px; + font-weight: 400; + line-height: 1em; } + .create-oss-reports section { + padding: 24px 24px 0; } + .create-oss-reports section .oss-report-options .select2-container { + min-width: 400px; } + .create-oss-reports section .oss-report-options td, .create-oss-reports section .oss-report-options th { + vertical-align: middle; + line-height: 1.75em; + padding: 0 0 24px; } + .create-oss-reports section .oss-report-options th { + width: 25%; + padding-right: 20px; } + .create-oss-reports section .oss-report-options th label { + color: #555; + font-weight: 400; + position: relative; + display: block; } + .create-oss-reports section .oss-report-hidden { + display: none; } + .create-oss-reports .oss-actions { + overflow: hidden; + border-top: 1px solid #eee; + margin: 0; + padding: 23px 24px 24px; + line-height: 3em; + display: flex; + flex-wrap: wrap; + justify-content: flex-end; } + .create-oss-reports .oss-actions .button { + font-size: 1.25em; + padding: 0.5em 1em !important; + line-height: 1.5em !important; + margin-right: .5em; + margin-bottom: 2px; + height: auto !important; + border-radius: 4px; + opacity: 1; } + +.woocommerce_page_oss-reports .summary { + font-family: HelveticaNeue-Light,"Helvetica Neue Light","Helvetica Neue",sans-serif; + font-weight: 400; + line-height: 1.6em; + font-size: 16px; } + +.woocommerce_page_oss-reports .tablenav .actions { + overflow: visible; } + +.woocommerce_page_oss-reports .tablenav .select2-container { + float: left; + width: 240px !important; + font-size: 14px; + vertical-align: middle; + margin: 1px 6px 4px 1px; } + .woocommerce_page_oss-reports .tablenav .select2-container .select2-selection--single { + height: 32px; } + .woocommerce_page_oss-reports .tablenav .select2-container .select2-selection--single .select2-selection__rendered { + line-height: 29px; } + .woocommerce_page_oss-reports .tablenav .select2-container .select2-selection--single .select2-selection__arrow { + height: 30px; } + +.woocommerce_page_oss-reports .tablenav select, .woocommerce_page_oss-reports .tablenav input { + line-height: 1; + height: 32px; } + +.woocommerce_page_oss-reports .tablenav input { + height: 31px; } + +.woocommerce_page_oss-reports .wp-list-table { + margin-top: 1em; } + .woocommerce_page_oss-reports .wp-list-table td, .woocommerce_page_oss-reports .wp-list-table th { + padding: .5em 1em; + width: 10ch; + vertical-align: middle; } + .woocommerce_page_oss-reports .wp-list-table td, .woocommerce_page_oss-reports .wp-list-table tbody th { + line-height: 26px; } + .woocommerce_page_oss-reports .wp-list-table thead th { + padding: .5em 1em; } + .woocommerce_page_oss-reports .wp-list-table thead th.sortable a, .woocommerce_page_oss-reports .wp-list-table thead th.sorted a { + padding: 0; } + .woocommerce_page_oss-reports .wp-list-table thead th:last-child { + padding-right: 2em; } + .woocommerce_page_oss-reports .wp-list-table .check-column { + width: 16px; + white-space: nowrap; + padding: 1em 1em 1em 1em !important; + vertical-align: middle; } + .woocommerce_page_oss-reports .wp-list-table .check-column input { + vertical-align: text-top; + margin: 1px 0; } + .woocommerce_page_oss-reports .wp-list-table td.column-title { + font-weight: bold; } + .woocommerce_page_oss-reports .wp-list-table .column-title { + width: 20ch; } + .woocommerce_page_oss-reports .wp-list-table .column-actions { + width: 10ch; } + .woocommerce_page_oss-reports .wp-list-table .column-actions { + text-align: right; } + .woocommerce_page_oss-reports .wp-list-table .column-actions a.button { + text-indent: 9999px; + margin: 2px 0 2px 4px; + position: relative; + display: inline-block; + padding: 0; + height: 2em; + width: 2em; + overflow: hidden; + vertical-align: middle; } + .woocommerce_page_oss-reports .wp-list-table .column-actions a.button::after { + font-family: Dashicons; + margin: 0; + margin-top: 2px; + speak: none; + font-weight: 400; + font-variant: normal; + text-transform: none; + text-indent: 0; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + text-align: center; + line-height: 1.85; } + .woocommerce_page_oss-reports .wp-list-table .column-actions a.button.view::after { + font-family: WooCommerce; + content: "\e010"; } + .woocommerce_page_oss-reports .wp-list-table .column-actions a.button.refresh::after { + content: "\f515"; } + .woocommerce_page_oss-reports .wp-list-table .column-actions a.button.delete, .woocommerce_page_oss-reports .wp-list-table .column-actions a.button.cancel { + border-color: #a00; + color: #a00; } + .woocommerce_page_oss-reports .wp-list-table .column-actions a.button.delete:focus, .woocommerce_page_oss-reports .wp-list-table .column-actions a.button.cancel:focus { + box-shadow: 0 0 0 1px #a00; + border-color: #a00; + color: #a00; } + .woocommerce_page_oss-reports .wp-list-table .column-actions a.button.delete:hover, .woocommerce_page_oss-reports .wp-list-table .column-actions a.button.cancel:hover { + border-color: #910000; + color: #910000; } + .woocommerce_page_oss-reports .wp-list-table .column-actions a.button.delete::after, .woocommerce_page_oss-reports .wp-list-table .column-actions a.button.cancel::after { + font-family: Dashicons; + content: "\f182"; } + .woocommerce_page_oss-reports .wp-list-table .column-actions a.button.export::after, .woocommerce_page_oss-reports .wp-list-table .column-actions a.button.export_bop::after { + content: "\f103"; } + .woocommerce_page_oss-reports .wp-list-table .column-address, .woocommerce_page_oss-reports .wp-list-table .column-sender { + width: 20ch; } + .woocommerce_page_oss-reports .wp-list-table .column-items { + width: 20ch; } + .woocommerce_page_oss-reports .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview { + font-size: .9em; + border-spacing: 0; } + .woocommerce_page_oss-reports .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview thead th { + color: #adadad; + padding-top: 0; + font-size: 1.1em; } + .woocommerce_page_oss-reports .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview tr td { + border-bottom: 1px solid #ccc !important; } + .woocommerce_page_oss-reports .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview tr:last-child td { + border-bottom: none !important; } + .woocommerce_page_oss-reports .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview th, .woocommerce_page_oss-reports .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview td { + padding: .3em 0; + vertical-align: top; + line-height: 20px; } + .woocommerce_page_oss-reports .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview th.wc-gzd-shipment-item-column-name, .woocommerce_page_oss-reports .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview td.wc-gzd-shipment-item-column-name { + width: 70%; } + .woocommerce_page_oss-reports .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview th.wc-gzd-shipment-item-column-name small, .woocommerce_page_oss-reports .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview td.wc-gzd-shipment-item-column-name small { + color: #999; + font-size: 12px; } + .woocommerce_page_oss-reports .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview th.wc-gzd-shipment-item-column-quantity, .woocommerce_page_oss-reports .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview td.wc-gzd-shipment-item-column-quantity { + text-align: right; + padding-right: .5em; } \ No newline at end of file diff --git a/packages/one-stop-shop-woocommerce/assets/css/admin.min.css b/packages/one-stop-shop-woocommerce/assets/css/admin.min.css new file mode 100644 index 000000000..bb53cb729 --- /dev/null +++ b/packages/one-stop-shop-woocommerce/assets/css/admin.min.css @@ -0,0 +1 @@ +p.oss-woocommerce-additional-desc{margin-top:1em!important;line-height:1.5em;background:#fff;padding:.5em;font-style:normal;font-size:14px;box-shadow:0 1px 1px 0 rgba(0,0,0,.1)}h2.oss-woocommerce-settings-title{margin-top:1.5em}h2.oss-woocommerce-settings-title .page-title-action{top:0}.oss-add-tax-class-by-country-template{display:none}a.oss-remove-tax-class-by-country{text-indent:0;overflow:hidden;color:#b32d2e;text-decoration:none;vertical-align:middle}p.oss-tax-class-by-country-field{display:flex;flex-wrap:wrap;align-items:center}p.oss-tax-class-by-country-field label{width:100%}p.oss-tax-class-by-country-field select{width:auto;flex-grow:1;flex-shrink:0;flex-basis:50%}p.oss-tax-class-by-country-field a.oss-remove-tax-class-by-country{margin-left:.5em}p.oss-add-tax-class-by-country-field{display:flex;align-items:center;width:100%}p.oss-add-tax-class-by-country-field a.oss-remove-tax-class-by-country{margin-left:.5em}p.oss-add-tax-class-by-country-field label{width:auto;flex-grow:0;flex-shrink:0;flex-basis:30%;margin-right:1em}p.oss-add-tax-class-by-country-field select.oss-tax-class-new-class{width:auto;flex-grow:1;flex-shrink:0;flex-basis:50%}.oss-observer-total{font-size:1.5em;background:#b1dabc;color:#1d4026;padding:3px;border-radius:2px}.oss-observer-total.observer-total-red{background:#dab1b4;color:#401d1d}.oss-settings-learn-more,.oss-settings-refresh-tax-rates{margin-left:.5em}.oss-observer-date-end{color:#646970;font-size:12px;margin-left:.5em}.oss-woo-status{background:#eee;padding:.2em .5em;font-size:.9em;border-radius:3px;display:inline-flex;white-space:nowrap}.oss-woo-status.report-status-pending{background:#f8dda7;color:#94660c}.oss-woo-status.report-status-failed{background:#eba3a3;color:#761919}.oss-woo-status.report-status-completed{background:#c6e1c6;color:#5b841b}.create-oss-reports{text-align:center;max-width:700px;margin:40px auto}.create-oss-reports .create-oss-report{background:#fff;overflow:hidden;padding:0;margin:0 0 16px;box-shadow:0 1px 3px rgba(0,0,0,.13);color:#555;text-align:left}.create-oss-reports header{border-bottom:1px solid #eee;margin:0;padding:24px 24px 0}.create-oss-reports header h2{margin:0 0 24px;color:#555;font-size:24px;font-weight:400;line-height:1em}.create-oss-reports section{padding:24px 24px 0}.create-oss-reports section .oss-report-options .select2-container{min-width:400px}.create-oss-reports section .oss-report-options td,.create-oss-reports section .oss-report-options th{vertical-align:middle;line-height:1.75em;padding:0 0 24px}.create-oss-reports section .oss-report-options th{width:25%;padding-right:20px}.create-oss-reports section .oss-report-options th label{color:#555;font-weight:400;position:relative;display:block}.create-oss-reports section .oss-report-hidden{display:none}.create-oss-reports .oss-actions{overflow:hidden;border-top:1px solid #eee;margin:0;padding:23px 24px 24px;line-height:3em;display:flex;flex-wrap:wrap;justify-content:flex-end}.create-oss-reports .oss-actions .button{font-size:1.25em;padding:.5em 1em!important;line-height:1.5em!important;margin-right:.5em;margin-bottom:2px;height:auto!important;border-radius:4px;opacity:1}.woocommerce_page_oss-reports .summary{font-family:HelveticaNeue-Light,"Helvetica Neue Light","Helvetica Neue",sans-serif;font-weight:400;line-height:1.6em;font-size:16px}.woocommerce_page_oss-reports .tablenav .actions{overflow:visible}.woocommerce_page_oss-reports .tablenav .select2-container{float:left;width:240px!important;font-size:14px;vertical-align:middle;margin:1px 6px 4px 1px}.woocommerce_page_oss-reports .tablenav .select2-container .select2-selection--single{height:32px}.woocommerce_page_oss-reports .tablenav .select2-container .select2-selection--single .select2-selection__rendered{line-height:29px}.woocommerce_page_oss-reports .tablenav .select2-container .select2-selection--single .select2-selection__arrow{height:30px}.woocommerce_page_oss-reports .tablenav input,.woocommerce_page_oss-reports .tablenav select{line-height:1;height:32px}.woocommerce_page_oss-reports .tablenav input{height:31px}.woocommerce_page_oss-reports .wp-list-table{margin-top:1em}.woocommerce_page_oss-reports .wp-list-table td,.woocommerce_page_oss-reports .wp-list-table th{padding:.5em 1em;width:10ch;vertical-align:middle}.woocommerce_page_oss-reports .wp-list-table tbody th,.woocommerce_page_oss-reports .wp-list-table td{line-height:26px}.woocommerce_page_oss-reports .wp-list-table thead th{padding:.5em 1em}.woocommerce_page_oss-reports .wp-list-table thead th.sortable a,.woocommerce_page_oss-reports .wp-list-table thead th.sorted a{padding:0}.woocommerce_page_oss-reports .wp-list-table thead th:last-child{padding-right:2em}.woocommerce_page_oss-reports .wp-list-table .check-column{width:16px;white-space:nowrap;padding:1em 1em 1em 1em!important;vertical-align:middle}.woocommerce_page_oss-reports .wp-list-table .check-column input{vertical-align:text-top;margin:1px 0}.woocommerce_page_oss-reports .wp-list-table td.column-title{font-weight:700}.woocommerce_page_oss-reports .wp-list-table .column-title{width:20ch}.woocommerce_page_oss-reports .wp-list-table .column-actions{width:10ch}.woocommerce_page_oss-reports .wp-list-table .column-actions{text-align:right}.woocommerce_page_oss-reports .wp-list-table .column-actions a.button{text-indent:9999px;margin:2px 0 2px 4px;position:relative;display:inline-block;padding:0;height:2em;width:2em;overflow:hidden;vertical-align:middle}.woocommerce_page_oss-reports .wp-list-table .column-actions a.button::after{font-family:Dashicons;margin:0;margin-top:2px;speak:none;font-weight:400;font-variant:normal;text-transform:none;text-indent:0;position:absolute;top:0;left:0;width:100%;height:100%;text-align:center;line-height:1.85}.woocommerce_page_oss-reports .wp-list-table .column-actions a.button.view::after{font-family:WooCommerce;content:"\e010"}.woocommerce_page_oss-reports .wp-list-table .column-actions a.button.refresh::after{content:"\f515"}.woocommerce_page_oss-reports .wp-list-table .column-actions a.button.cancel,.woocommerce_page_oss-reports .wp-list-table .column-actions a.button.delete{border-color:#a00;color:#a00}.woocommerce_page_oss-reports .wp-list-table .column-actions a.button.cancel:focus,.woocommerce_page_oss-reports .wp-list-table .column-actions a.button.delete:focus{box-shadow:0 0 0 1px #a00;border-color:#a00;color:#a00}.woocommerce_page_oss-reports .wp-list-table .column-actions a.button.cancel:hover,.woocommerce_page_oss-reports .wp-list-table .column-actions a.button.delete:hover{border-color:#910000;color:#910000}.woocommerce_page_oss-reports .wp-list-table .column-actions a.button.cancel::after,.woocommerce_page_oss-reports .wp-list-table .column-actions a.button.delete::after{font-family:Dashicons;content:"\f182"}.woocommerce_page_oss-reports .wp-list-table .column-actions a.button.export::after,.woocommerce_page_oss-reports .wp-list-table .column-actions a.button.export_bop::after{content:"\f103"}.woocommerce_page_oss-reports .wp-list-table .column-address,.woocommerce_page_oss-reports .wp-list-table .column-sender{width:20ch}.woocommerce_page_oss-reports .wp-list-table .column-items{width:20ch}.woocommerce_page_oss-reports .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview{font-size:.9em;border-spacing:0}.woocommerce_page_oss-reports .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview thead th{color:#adadad;padding-top:0;font-size:1.1em}.woocommerce_page_oss-reports .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview tr td{border-bottom:1px solid #ccc!important}.woocommerce_page_oss-reports .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview tr:last-child td{border-bottom:none!important}.woocommerce_page_oss-reports .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview td,.woocommerce_page_oss-reports .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview th{padding:.3em 0;vertical-align:top;line-height:20px}.woocommerce_page_oss-reports .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview td.wc-gzd-shipment-item-column-name,.woocommerce_page_oss-reports .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview th.wc-gzd-shipment-item-column-name{width:70%}.woocommerce_page_oss-reports .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview td.wc-gzd-shipment-item-column-name small,.woocommerce_page_oss-reports .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview th.wc-gzd-shipment-item-column-name small{color:#999;font-size:12px}.woocommerce_page_oss-reports .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview td.wc-gzd-shipment-item-column-quantity,.woocommerce_page_oss-reports .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview th.wc-gzd-shipment-item-column-quantity{text-align:right;padding-right:.5em} \ No newline at end of file diff --git a/packages/one-stop-shop-woocommerce/assets/css/admin.scss b/packages/one-stop-shop-woocommerce/assets/css/admin.scss new file mode 100644 index 000000000..ff78032ad --- /dev/null +++ b/packages/one-stop-shop-woocommerce/assets/css/admin.scss @@ -0,0 +1,427 @@ +p.oss-woocommerce-additional-desc { + margin-top: 1em !important; + line-height: 1.5em; + background: #fff; + padding: .5em; + font-style: normal; + font-size: 14px; + box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1); +} + +h2.oss-woocommerce-settings-title { + margin-top: 1.5em; + + .page-title-action { + top: 0; + } +} + +.oss-add-tax-class-by-country-template { + display: none; +} + +a.oss-remove-tax-class-by-country { + text-indent: 0; + overflow: hidden; + color: #b32d2e; + text-decoration: none; + vertical-align: middle; +} + +p.oss-tax-class-by-country-field { + display: flex; + flex-wrap: wrap; + align-items: center; + + label { + width: 100%; + } + + select { + width: auto; + flex-grow: 1; + flex-shrink: 0; + flex-basis: 50%; + } + + a.oss-remove-tax-class-by-country { + margin-left: .5em; + } +} + +p.oss-add-tax-class-by-country-field { + display: flex; + align-items: center; + width: 100%; + + a.oss-remove-tax-class-by-country { + margin-left: .5em; + } + + label { + width: auto; + flex-grow: 0; + flex-shrink: 0; + flex-basis: 30%; + margin-right: 1em; + } + + select.oss-tax-class-new-class { + width: auto; + flex-grow: 1; + flex-shrink: 0; + flex-basis: 50%; + } +} + +.oss-observer-total { + font-size: 1.5em; + background: #b1dabc; + color: #1d4026; + padding: 3px; + border-radius: 2px; + + &.observer-total-red { + background: #dab1b4; + color: #401d1d; + } +} + +.oss-settings-learn-more, .oss-settings-refresh-tax-rates { + margin-left: .5em; +} + +.oss-observer-date-end { + color: #646970; + font-size: 12px; + margin-left: .5em; +} + +.oss-woo-status { + background: #eee; + padding: .2em .5em; + font-size: .9em; + border-radius: 3px; + display: inline-flex; + white-space: nowrap; + + &.report-status-pending { + background: #f8dda7; + color: #94660c; + } + + &.report-status-failed { + background: #eba3a3; + color: #761919; + } + + &.report-status-completed { + background: #c6e1c6; + color: #5b841b; + } +} + +.create-oss-reports { + text-align: center; + max-width: 700px; + margin: 40px auto; + + .create-oss-report { + background: #fff; + overflow: hidden; + padding: 0; + margin: 0 0 16px; + box-shadow: 0 1px 3px rgba(0,0,0,.13); + color: #555; + text-align: left; + } + + header { + border-bottom: 1px solid #eee; + margin: 0; + padding: 24px 24px 0; + + h2 { + margin: 0 0 24px; + color: #555; + font-size: 24px; + font-weight: 400; + line-height: 1em; + } + } + + section { + padding: 24px 24px 0; + + .oss-report-options { + .select2-container { + min-width: 400px; + } + + td, th { + vertical-align: middle; + line-height: 1.75em; + padding: 0 0 24px; + } + + th { + width: 25%; + padding-right: 20px; + + label { + color: #555; + font-weight: 400; + position: relative; + display: block; + } + } + } + + .oss-report-hidden { + display: none; + } + } + + .oss-actions { + overflow: hidden; + border-top: 1px solid #eee; + margin: 0; + padding: 23px 24px 24px; + line-height: 3em; + display: flex; + flex-wrap: wrap; + justify-content: flex-end; + + .button { + font-size: 1.25em; + padding: .5em 1em!important; + line-height: 1.5em!important; + margin-right: .5em; + margin-bottom: 2px; + height: auto!important; + border-radius: 4px; + opacity: 1; + } + } +} + +.woocommerce_page_oss-reports { + .summary { + font-family: HelveticaNeue-Light,"Helvetica Neue Light","Helvetica Neue",sans-serif; + font-weight: 400; + line-height: 1.6em; + font-size: 16px; + } + + .tablenav { + .actions { + overflow: visible; + } + + .select2-container { + float: left; + width: 240px!important; + font-size: 14px; + vertical-align: middle; + margin: 1px 6px 4px 1px; + + .select2-selection--single { + height: 32px; + + .select2-selection__rendered { + line-height: 29px; + } + + .select2-selection__arrow { + height: 30px; + } + } + } + + select, input { + line-height: 1; + height: 32px; + } + + input { + height: 31px; + } + } + + .wp-list-table { + margin-top: 1em; + + td, th { + padding: .5em 1em; + width: 10ch; + vertical-align: middle; + } + + td, tbody th { + line-height: 26px; + } + + thead { + th { + padding: .5em 1em; + + &.sortable a, &.sorted a { + padding: 0; + } + + &:last-child { + padding-right: 2em; + } + } + } + + .check-column { + width: 16px; + white-space: nowrap; + padding: 1em 1em 1em 1em !important; + vertical-align: middle; + + input { + vertical-align: text-top; + margin: 1px 0; + } + } + + td.column-title { + font-weight: bold; + } + + .column-title { + width: 20ch; + } + + .column-actions { + width: 10ch; + } + + .column-actions { + text-align: right; + + a.button { + text-indent: 9999px; + margin: 2px 0 2px 4px; + position: relative; + display: inline-block; + padding: 0; + height: 2em; + width: 2em; + overflow: hidden; + vertical-align: middle; + + &::after { + font-family: Dashicons; + margin: 0; + margin-top: 2px; + speak: none; + font-weight: 400; + font-variant: normal; + text-transform: none; + text-indent: 0; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + text-align: center; + line-height: 1.85; + } + + &.view::after { + font-family: WooCommerce; + content: "\e010"; + } + + &.refresh::after { + content: "\f515"; + } + + &.delete, &.cancel { + border-color: #a00; + color: #a00; + + &:focus { + box-shadow: 0 0 0 1px #a00; + border-color: #a00; + color: #a00; + } + + &:hover { + border-color: darken( #a00, 5% ); + color: darken( #a00, 5% ); + } + + &::after { + font-family: Dashicons; + content: "\f182"; + } + } + + &.export::after, &.export_bop::after { + content: "\f103"; + } + } + } + + .column-address, .column-sender { + width: 20ch; + } + + .column-items { + width: 20ch; + } + + #the-list { + .column-items { + table.wc-gzd-shipments-preview { + font-size: .9em; + border-spacing: 0; + + thead { + th { + color: #adadad; + padding-top: 0; + font-size: 1.1em; + } + } + + tr { + td { + border-bottom: 1px solid #ccc !important; + } + + &:last-child { + td { + border-bottom: none !important; + } + } + } + + th, td { + padding: .3em 0; + vertical-align: top; + line-height: 20px; + + &.wc-gzd-shipment-item-column-name { + width: 70%; + + small { + color: #999; + font-size: 12px; + } + } + + &.wc-gzd-shipment-item-column-quantity { + text-align: right; + padding-right: .5em; + } + } + } + } + } + } +} \ No newline at end of file diff --git a/packages/one-stop-shop-woocommerce/assets/js/admin.js b/packages/one-stop-shop-woocommerce/assets/js/admin.js new file mode 100644 index 000000000..2ede63f8f --- /dev/null +++ b/packages/one-stop-shop-woocommerce/assets/js/admin.js @@ -0,0 +1,104 @@ +window.oss = window.oss || {}; + +( function( $, oss ) { + oss.admin = { + + params: {}, + dates: false, + + init: function() { + var self = oss.admin; + self.params = oss_admin_params; + + $( document ) + .on( 'change', 'select#oss-report-type', self.onChangeReportType ) + .on( 'click', 'a.oss-add-new-tax-class-by-country', self.onAddNewTaxClassCountry ) + .on( 'click', 'a.oss-remove-tax-class-by-country', self.onRemoveTaxClassCountry ); + + if ( $( 'select#oss-report-type' ).length > 0 ) { + $( 'select#oss-report-type' ).trigger( 'change' ); + } + + if ( $( '.oss_range_datepicker' ).length > 0 ) { + self.initDatePicker(); + } + + $( document.body ).on( 'init_tooltips', function() { + self.initTipTip(); + }); + + self.initTipTip(); + }, + + onAddNewTaxClassCountry: function() { + var $parent = $( this ).parents( '#general_product_data' ); + + if ( $parent.length === 0 ) { + $parent = $( this ).parents( '.woocommerce_variable_attributes' ); + } + + var $template = $parent.find( '.oss-add-tax-class-by-country-template:first' ).clone(); + + $template.removeClass( 'oss-add-tax-class-by-country-template' ).addClass( 'oss-add-tax-class-by-country-new' ); + $parent.find( '.oss-new-tax-class-by-country-placeholder' ).append( $template ).show(); + + return false; + }, + + onRemoveTaxClassCountry: function() { + var $parent = $( this ).parents( '.form-field' ); + + // Trigger change to notify Woo about an update (variations). + $parent.find( 'select' ).trigger( 'change' ); + $parent.remove(); + + return false; + }, + + initDatePicker: function() { + var self = oss.admin; + + self.dates = $( '.oss_range_datepicker' ).datepicker({ + changeMonth: true, + changeYear: true, + defaultDate: '', + dateFormat: 'yy-mm-dd', + numberOfMonths: 1, + minDate: '-20Y', + maxDate: '+0D', + showButtonPanel: true, + showOn: 'focus', + buttonImageOnly: true, + onSelect: function() { + var option = $( this ).is( '.from' ) ? 'minDate' : 'maxDate', + date = $( this ).datepicker( 'getDate' ); + + self.dates.not( this ).datepicker( 'option', option, date ); + } + }); + }, + + onChangeReportType: function() { + var type = $( this ).val(); + + $( '.oss-report-hidden' ).hide(); + + if ( $( '.oss-report-' + type ).length > 0 ) { + $( '.oss-report-' + type ).show(); + } + }, + + initTipTip: function() { + $( '.column-actions .oss-woo-action-button' ).tipTip( { + 'fadeIn': 50, + 'fadeOut': 50, + 'delay': 200 + }); + } + }; + + $( document ).ready( function() { + oss.admin.init(); + }); + +})( jQuery, window.oss ); diff --git a/packages/one-stop-shop-woocommerce/assets/js/admin.min.js b/packages/one-stop-shop-woocommerce/assets/js/admin.min.js new file mode 100644 index 000000000..cadebe2f0 --- /dev/null +++ b/packages/one-stop-shop-woocommerce/assets/js/admin.min.js @@ -0,0 +1 @@ +window.oss=window.oss||{},function(a,e){e.admin={params:{},dates:!1,init:function(){var t=e.admin;t.params=oss_admin_params,a(document).on("change","select#oss-report-type",t.onChangeReportType).on("click","a.oss-add-new-tax-class-by-country",t.onAddNewTaxClassCountry).on("click","a.oss-remove-tax-class-by-country",t.onRemoveTaxClassCountry),0@0 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\n" +"Language-Team: \n" +"Language: de_DE\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 3.1\n" +"X-Poedit-Basepath: ../..\n" +"X-Poedit-Flags-xgettext: --add-comments=translators:\n" +"X-Poedit-WPHeader: one-stop-shop-woocommerce.php\n" +"X-Poedit-SourceCharset: UTF-8\n" +"X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;" +"esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;_n_noop:1,2;" +"_nx_noop:3c,1,2;__ngettext_noop:1,2\n" +"X-Poedit-SearchPath-0: .\n" +"X-Poedit-SearchPathExcluded-0: *.min.js\n" +"X-Poedit-SearchPathExcluded-1: vendor\n" +"X-Poedit-SearchPathExcluded-2: node_modules\n" +"X-Poedit-SearchPathExcluded-3: build\n" + +#: libs/woocommerce-eu-tax-helper/src/Helper.php:212 +msgid "Reduced rate" +msgstr "" + +#: libs/woocommerce-eu-tax-helper/src/Helper.php:213 +msgctxt "tax-helper-tax-class-name" +msgid "Greater reduced rate" +msgstr "Zusätzlicher reduzierter Preis" + +#: libs/woocommerce-eu-tax-helper/src/Helper.php:214 +msgctxt "tax-helper-tax-class-name" +msgid "Super reduced rate" +msgstr "Stark reduzierter Preis" + +#: libs/woocommerce-eu-tax-helper/src/Helper.php:617 +msgctxt "tax-helper" +msgid "Madeira" +msgstr "Madeira" + +#: libs/woocommerce-eu-tax-helper/src/Helper.php:624 +msgctxt "tax-helper" +msgid "Acores" +msgstr "Azoren" + +#: libs/woocommerce-eu-tax-helper/src/Helper.php:660 +msgctxt "tax-helper" +msgid "Northern Ireland" +msgstr "Nordirland" + +#: libs/woocommerce-eu-tax-helper/src/Helper.php:673 +msgctxt "tax-helper-rate-import" +msgid "Exempt" +msgstr "Ausnahme" + +#: libs/woocommerce-eu-tax-helper/src/Helper.php:742 +#, php-format +msgctxt "tax-helper-rate-import" +msgid "VAT %1$s %% %2$s" +msgstr "MwSt. %1$s %% %2$s" + +#. translators: 1: composer command. 2: plugin directory +#: one-stop-shop-woocommerce.php:44 one-stop-shop-woocommerce.php:62 +#, php-format +msgctxt "oss" +msgid "" +"Your installation of the One Stop Shop feature plugin is incomplete. Please " +"run %1$s within the %2$s directory." +msgstr "" +"Deine Installation des One Stop Shop Feature Plugins ist nicht komplett. " +"Bitte führe %1$s innerhalb des %2$s Verzeichnisses aus." + +#: src/Admin.php:78 src/Admin.php:79 +msgctxt "oss" +msgid "Refresh VAT rates (OSS)" +msgstr "EU Steuersätze erneuern (OSS)" + +#: src/Admin.php:83 +msgctxt "oss" +msgid "Note:" +msgstr "Hinweis:" + +#: src/Admin.php:84 +#, php-format +msgctxt "oss" +msgid "" +"This option will delete all of your current EU VAT rates and re-import them " +"based on your current OSS status." +msgstr "" +"Diese Option löscht alle deine aktuellen EU Steuersätze und importiert sie " +"anschließend auf Basis deines OSS Status neu." + +#: src/Admin.php:214 +#, php-format +msgctxt "oss" +msgid "" +"Seems like you have reached (or are close to reaching) the delivery " +"threshold for the current year. Please make sure to check the report details and take action in case necessary." +msgstr "" +"Du bist kurz davor oder hast bereits die Lieferschwelle für das aktuelle " +"Jahr überschritten. Bitte prüfe die Details " +"des Berichts und unternimm weitere Schritte." + +#: src/Admin.php:218 +msgctxt "oss" +msgid "Delivery threshold reached (OSS)" +msgstr "Lieferschwelle erreicht (OSS)" + +#: src/Admin.php:448 src/SettingsPage.php:17 +msgctxt "oss" +msgid "OSS" +msgstr "OSS" + +#: src/Admin.php:448 src/Admin.php:566 src/SettingsPage.php:23 +msgctxt "oss" +msgid "One Stop Shop" +msgstr "One Stop Shop" + +#: src/Admin.php:469 src/Package.php:365 +#, php-format +msgctxt "oss" +msgid "Q%1$s/%2$s" +msgstr "Q%1$s/%2$s" + +#: src/Admin.php:478 src/Package.php:370 +#, php-format +msgctxt "oss" +msgid "%1$s/%2$s" +msgstr "%1$s/%2$s" + +#: src/Admin.php:486 +msgctxt "oss" +msgid "New Report" +msgstr "Neuer Bericht" + +#: src/Admin.php:493 +msgctxt "oss" +msgid "Type" +msgstr "Typ" + +#: src/Admin.php:505 +msgctxt "oss" +msgid "Year" +msgstr "Jahr" + +#: src/Admin.php:517 +msgctxt "oss" +msgid "Quarter" +msgstr "Quartal" + +#: src/Admin.php:529 +msgctxt "oss" +msgid "Month" +msgstr "Monat" + +#: src/Admin.php:541 +msgctxt "oss" +msgid "Date range" +msgstr "Zeitraum" + +#: src/Admin.php:553 +msgctxt "oss" +msgid "Start report" +msgstr "Bericht starten" + +#: src/Admin.php:567 +msgctxt "oss" +msgid "New report" +msgstr "Neuer Bericht" + +#: src/Admin.php:609 +msgctxt "oss" +msgid "View" +msgstr "Ansehen" + +#: src/Admin.php:613 +msgctxt "oss" +msgid "Export" +msgstr "Exportieren" + +#: src/Admin.php:617 +msgctxt "oss" +msgid "Export BOP" +msgstr "BOP-CSV exportieren" + +#: src/Admin.php:621 +msgctxt "oss" +msgid "Refresh" +msgstr "Aktualisieren" + +#: src/Admin.php:625 +msgctxt "oss" +msgid "Delete" +msgstr "Löschen" + +#: src/Admin.php:631 +msgctxt "oss" +msgid "Cancel" +msgstr "Abbrechen" + +#: src/Admin.php:669 +msgctxt "oss" +msgid "Country" +msgstr "Land" + +#: src/Admin.php:670 +msgctxt "oss" +msgid "Tax Rate" +msgstr "Steuersatz" + +#: src/Admin.php:671 +msgctxt "oss" +msgid "Net Total" +msgstr "Nettobetrag" + +#: src/Admin.php:672 +msgctxt "oss" +msgid "Tax Total" +msgstr "Steuerbertrag" + +#: src/Admin.php:703 +#, php-format +msgctxt "oss" +msgid "%1$s %%" +msgstr "%1$s %%" + +#: src/Admin.php:716 +#, php-format +msgctxt "oss" +msgid "" +"Currently processed %1$s orders. Next iteration is scheduled for %2$s. Find pending actions" +msgstr "" +"Aktuell %1$s Bestellung verarbeitet. Nächster Durchlauf planmäßig am %2$s. " +"Offene Aktionen finden" + +#: src/Admin.php:716 +msgctxt "oss" +msgid "Not yet known" +msgstr "Noch nicht bekannt" + +#: src/Admin.php:747 src/ReportTable.php:39 src/SettingsPage.php:23 +msgctxt "oss" +msgid "Reports" +msgstr "Berichte" + +#: src/AdminNote.php:46 +msgctxt "oss" +msgid "Dismiss" +msgstr "Ausblenden" + +#: src/AsyncReportGenerator.php:258 +msgctxt "oss" +msgid "No orders found." +msgstr "Keine Bestellungen gefunden." + +#: src/CSVExporter.php:54 +msgctxt "oss" +msgid "Country code" +msgstr "Land des Verbrauchs" + +#: src/CSVExporter.php:55 +msgctxt "oss" +msgid "Tax rate" +msgstr "Umsatzsteuersatz" + +#: src/CSVExporter.php:56 +msgctxt "oss" +msgid "Taxable base" +msgstr "Nettobetrag" + +#: src/CSVExporter.php:57 +msgctxt "oss" +msgid "Amount" +msgstr "Umsatzsteuerbetrag" + +#: src/DeliveryThresholdEmailNotification.php:19 +msgctxt "oss" +msgid "OSS Delivery Threshold Notification" +msgstr "OSS Lieferschwelle Benachrichtigung" + +#: src/DeliveryThresholdEmailNotification.php:20 +msgctxt "oss" +msgid "" +"This email notifies shop owners in case the delivery threshold (OSS) is " +"close to being reached." +msgstr "" +"Diese E-Mail benachrichtigt den Shopbetreiber über eine in Kürze anstehende " +"Überschreitung der Lieferschwelle (OSS)." + +#: src/DeliveryThresholdEmailNotification.php:38 +msgctxt "oss" +msgid "[{site_title}]: OSS delivery threshold reached" +msgstr "[{site_title}]: OSS Lieferschwelle erreicht" + +#: src/DeliveryThresholdEmailNotification.php:48 +msgctxt "oss" +msgid "OSS delivery threshold reached" +msgstr "OSS Lieferschwelle erreicht" + +#: src/DeliveryThresholdWarning.php:14 +msgctxt "oss" +msgid "See details" +msgstr "Details ansehen" + +#: src/Package.php:178 +msgctxt "oss" +msgid "" +"To use the OSS for WooCommerce plugin please make sure that WooCommerce is " +"installed and activated." +msgstr "" +"Um das OSS für WooCommerce Plugin nutzen zu können muss WooCommerce " +"installiert und aktiviert sein." + +#: src/Package.php:350 src/ReportTable.php:40 +msgctxt "oss" +msgid "Report" +msgstr "Bericht" + +#: src/Package.php:374 +#, php-format +msgctxt "oss" +msgid "%1$s" +msgstr "%1$s" + +#: src/Package.php:379 +#, php-format +msgctxt "oss" +msgid "%1$s - %2$s" +msgstr "%1$s - %2$s" + +#: src/Package.php:384 +#, php-format +msgctxt "oss" +msgid "Observer %1$s" +msgstr "Beobachter %1$s" + +#: src/Package.php:626 +msgctxt "oss" +msgid "Quarterly" +msgstr "Quartalsweise" + +#: src/Package.php:627 +msgctxt "oss" +msgid "Yearly" +msgstr "Jährlich" + +#: src/Package.php:628 +msgctxt "oss" +msgid "Monthly" +msgstr "Monatlich" + +#: src/Package.php:629 +msgctxt "oss" +msgid "Custom" +msgstr "Individuell" + +#: src/Package.php:633 +msgctxt "oss" +msgid "Observer" +msgstr "Beobachter" + +#: src/Package.php:647 +msgctxt "oss" +msgid "Pending" +msgstr "In Bearbeitung" + +#: src/Package.php:648 +msgctxt "oss" +msgid "Completed" +msgstr "Fertiggestellt" + +#: src/Package.php:649 +msgctxt "oss" +msgid "Failed" +msgstr "Fehlgeschlagen" + +#: src/ReportTable.php:124 +#, php-format +msgctxt "oss" +msgid "%d report deleted." +msgid_plural "%d reports deleted." +msgstr[0] "%d Bericht gelöscht." +msgstr[1] "%d Berichte gelöscht." + +#: src/ReportTable.php:187 +msgctxt "oss" +msgid "No reports found" +msgstr "Keine Berichte gefunden" + +#: src/ReportTable.php:228 +#, php-format +msgctxt "oss" +msgid "All (%s)" +msgid_plural "All (%s)" +msgstr[0] "Alle (%s)" +msgstr[1] "Alle (%s)" + +#: src/ReportTable.php:255 +#, php-format +msgctxt "oss" +msgid " (%s)" +msgid_plural " (%s)" +msgstr[0] " (%s)" +msgstr[1] " (%s)" + +#: src/ReportTable.php:326 +msgctxt "oss" +msgid "Filter" +msgstr "Filtern" + +#: src/ReportTable.php:353 +msgctxt "oss" +msgid "Title" +msgstr "Titel" + +#: src/ReportTable.php:354 +msgctxt "oss" +msgid "Start" +msgstr "Start" + +#: src/ReportTable.php:355 +msgctxt "oss" +msgid "End" +msgstr "Ende" + +#: src/ReportTable.php:356 templates/emails/admin-delivery-threshold.php:25 +msgctxt "oss" +msgid "Net total" +msgstr "Nettobetrag" + +#: src/ReportTable.php:357 templates/emails/admin-delivery-threshold.php:26 +msgctxt "oss" +msgid "Tax total" +msgstr "Steuerbertrag" + +#: src/ReportTable.php:358 +msgctxt "oss" +msgid "Status" +msgstr "Status" + +#: src/ReportTable.php:359 +msgctxt "oss" +msgid "Actions" +msgstr "Aktionen" + +#: src/ReportTable.php:423 +#, php-format +msgctxt "oss" +msgid "Select %s" +msgstr "%s auswählen" + +#: src/ReportTable.php:516 +msgctxt "oss" +msgid "Delete Permanently" +msgstr "Unwiderruflich löschen" + +#: src/Settings.php:16 +msgctxt "oss" +msgid "General" +msgstr "Allgemein" + +#: src/Settings.php:21 +msgctxt "oss" +msgid "" +"Find useful options regarding the One Stop Shop procedure here." +msgstr "" +"Finde hier nützliche Optionen zum One Stop Shop Verfahren." + +#: src/Settings.php:38 +msgctxt "oss" +msgid "OSS status" +msgstr "OSS Status" + +#: src/Settings.php:39 +msgctxt "oss" +msgid "Yes, I'm currently participating in the OSS procedure." +msgstr "Ja, ich nehme aktuell am One Stop Shop Verfahren teil." + +#: src/Settings.php:46 +msgctxt "oss" +msgid "Observation" +msgstr "Überwachung" + +#: src/Settings.php:47 +msgctxt "oss" +msgid "Automatically observe the delivery threshold of the current year." +msgstr "Überwache die Lieferschwelle des aktuellen Jahres automatisch." + +#: src/Settings.php:47 +msgctxt "oss" +msgid "" +"This option will automatically calculate the amount applicable for the OSS " +"procedure delivery threshold once per day for the current year. The report " +"will only recalculated for the days which are not yet subject to the " +"observation to save processing time." +msgstr "" +"Diese Option überwacht automatisch die Lieferschwelle des OSS Verfahrens für " +"das aktuelle Jahr, indem der dazugehörige Bericht täglich erweitert und " +"nachberechnet wird. Der Bericht wird nur für die Tage nachberechnet, für die " +"aktuell noch keine Überwachung stattfindet." + +#: src/Settings.php:59 +msgctxt "oss" +msgid "Delivery threshold" +msgstr "Lieferschwelle" + +#: src/Settings.php:72 +msgctxt "oss" +msgid "Participation" +msgstr "Teilnahme" + +#: src/Settings.php:79 +msgctxt "oss" +msgid "Report Order Date" +msgstr "Bericht Bestelldatum" + +#: src/Settings.php:80 +msgctxt "oss" +msgid "" +"Select the relevant order date to be used to determine whether to include an " +"order in a report." +msgstr "" +"Wähle das relevante Bestelldatum aus auf Basis dessen entschieden wird ob " +"eine Bestellung in einen Bericht inkludiert wird." + +#: src/Settings.php:85 +msgctxt "oss" +msgid "Date paid" +msgstr "Zahlungsdatum" + +#: src/Settings.php:86 +msgctxt "oss" +msgid "Date created" +msgstr "Erstellungsdatum" + +#: src/Settings.php:97 +msgctxt "oss" +msgid "Fixed gross prices" +msgstr "Feste Bruttopreise" + +#: src/Settings.php:98 +msgctxt "oss" +msgid "Apply the same gross price regardless of the tax rate for EU countries." +msgstr "Verwende den Bruttopreis für EU-Länder unabhängig vom Steuersatz." + +#: src/Settings.php:98 +msgctxt "oss" +msgid "" +"This option will make sure that your customers pay the same price no matter " +"the tax rate (based on the country chosen) to be applied." +msgstr "" +"Diese Option bewirkt, dass Kunden, unabhängig vom Land und damit vom " +"Steuersatz den selben Bruttopreis bezahlen." + +#: src/Settings.php:104 +msgctxt "oss" +msgid "Third countries" +msgstr "Drittländer" + +#: src/Settings.php:105 +msgctxt "oss" +msgid "Apply the same gross price for third countries too." +msgstr "Verwende den Bruttopreis auch für Drittländer." + +#: src/Settings.php:138 src/Settings.php:139 +msgctxt "oss" +msgid "Are you sure? Please backup your tax rates before proceeding." +msgstr "Bist du sicher? Bitte erstelle vorab ein Backup deiner Steuersätze." + +#: src/Settings.php:138 +msgctxt "oss" +msgid "End OSS participation" +msgstr "OSS Teilnahme beenden" + +#: src/Settings.php:138 +msgctxt "oss" +msgid "Start OSS participation" +msgstr "OSS Teilnahme starten" + +#: src/Settings.php:139 +msgctxt "oss" +msgid "refresh VAT rates" +msgstr "Steuersätze erneuern" + +#: src/Settings.php:140 +msgctxt "oss" +msgid "learn more" +msgstr "Mehr erfahren" + +#: src/Settings.php:142 +msgctxt "oss" +msgid "" +"Use this option to automatically adjust tax-related options in WooCommerce. " +"Warning: This option will delete your current tax rates and add new tax " +"rates based on your OSS participation status." +msgstr "" +"Nutze diese Option um deine Steuereinstellungen in WooCommerce automatisch " +"anpassen zu lassen. Achtung: Diese Option löscht deine aktuellen Steuersätze " +"und fügt neue Steuersätze basierend auf deinem OSS Status hinzu." + +#: src/Settings.php:174 +msgctxt "oss" +msgid "See status" +msgstr "Status ansehen" + +#: src/Settings.php:174 +msgctxt "oss" +msgid "Start initial report" +msgstr "Initialen Bericht erstellen" + +#: src/Settings.php:175 +#, php-format +msgctxt "oss" +msgid "Report not yet completed. %s" +msgstr "Bericht noch nicht abgeschlossen. %s" + +#: src/Settings.php:175 +#, php-format +msgctxt "oss" +msgid "Report not yet started. %s" +msgstr "Bericht noch nicht gestartet. %s" + +#: src/Settings.php:193 +msgctxt "oss-amounts" +msgid "of" +msgstr "von" + +#: src/Settings.php:193 +#, php-format +msgctxt "oss" +msgid "As of: %s" +msgstr "Stand: %s" + +#: src/Settings.php:193 +msgctxt "oss" +msgid "see details" +msgstr "Details ansehen" + +#: src/Settings.php:194 +#, php-format +msgctxt "oss" +msgid "" +"This value indicates your current net total amount applicable for the One " +"Stop Shop procedure delivery threshold of the current year. You should take " +"action in case the delivery threshold is or is close to being exceeded. Find out more about the calculation." +msgstr "" +"Dieser Wert entspricht der Bemessungsgrundlage (Nettobetrag) des aktuellen " +"Jahres für die Lieferschwelle des One Stop Shop Verfahrens. Du solltest " +"tätig werden, wenn die Lieferschwelle kurz vor einer Überschreitung steht " +"oder bereits überschritten wurde. Erfahre mehr über die " +"Berechnung." + +#: src/SettingsPage.php:23 +msgctxt "oss" +msgid "Learn More" +msgstr "Mehr erfahren" + +#: src/Tax.php:260 src/Tax.php:338 +#, php-format +msgctxt "oss" +msgid "Tax class (%s)" +msgstr "Steuerklasse (%s)" + +#: src/Tax.php:261 +msgctxt "oss" +msgid "Same as parent" +msgstr "Gleiche wie übergeordnet" + +#: src/Tax.php:263 src/Tax.php:296 src/Tax.php:340 src/Tax.php:374 +msgctxt "oss" +msgid "remove" +msgstr "Löschen" + +#: src/Tax.php:273 src/Tax.php:351 +msgctxt "oss" +msgid "Add country specific tax class (OSS)" +msgstr "Länderspezifische Steuerklasse hinzufügen (OSS)" + +#: src/Tax.php:280 src/Tax.php:358 +msgctxt "oss" +msgid "Select country" +msgstr "Land auswählen" + +#: src/Tax.php:305 src/Tax.php:315 +msgctxt "oss" +msgid "EU-wide" +msgstr "EU-weit" + +#. translators: %s: Customer billing full name +#: templates/emails/admin-delivery-threshold.php:19 +#, php-format +msgctxt "oss" +msgid "" +"Your OSS delivery threshold of %1$s has been reached. Please take action " +"immediately. Visit the OSS Settings Panel for details." +msgstr "" +"Deine OSS Lieferschwelle von %1$s wurde erreicht. Bitte werde umgehend " +"tätig. Besuche die OSS Einstellungen um Details zu " +"erfahren." + +#: templates/emails/admin-delivery-threshold.php:21 +msgctxt "oss" +msgid "Report Details" +msgstr "Details des Berichts" + +#: templates/emails/admin-delivery-threshold.php:24 +msgctxt "oss" +msgid "Period" +msgstr "Periode" + +#: templates/emails/admin-delivery-threshold.php:29 +msgctxt "oss" +msgid "See report details" +msgstr "Details des Berichts abrufen" + +#: templates/emails/plain/admin-delivery-threshold.php:17 +#, php-format +msgctxt "oss" +msgid "" +"Your OSS delivery threshold of %1$s has been reached. Please take action " +"immediately. Visit the OSS Settings Panel (%2$s) for details." +msgstr "" +"Deine OSS Lieferschwelle von %1$s wurde erreicht. Bitte werde umgehend " +"tätig. Besuche die OSS Einstellungen (%2$s) um Details zu erfahren." + +#. Plugin Name of the plugin/theme +msgid "One Stop Shop for WooCommerce" +msgstr "One Stop Shop für WooCommerce" + +#. Plugin URI of the plugin/theme +msgid "https://github.com/vendidero/one-stop-shop-woocommerce" +msgstr "https://github.com/vendidero/one-stop-shop-woocommerce" + +#. Description of the plugin/theme +msgid "Comply with the One Stop Shop procedure while using WooCommerce." +msgstr "Nutze das One Stop Shop Verfahren zusammen mit WooCommerce." + +#. Author of the plugin/theme +msgid "vendidero" +msgstr "vendidero" + +#. Author URI of the plugin/theme +msgid "https://vendidero.de" +msgstr "https://vendidero.de" + +#~ msgctxt "storeabill-core" +#~ msgid "Year" +#~ msgstr "Jahr" + +#~ msgctxt "storeabill-core" +#~ msgid "Quarter" +#~ msgstr "Quartal" + +#~ msgctxt "storeabill-core" +#~ msgid "Month" +#~ msgstr "Monat" + +#~ msgctxt "storeabill-core" +#~ msgid "Date range" +#~ msgstr "Zeitraum" + +#~ msgctxt "oss" +#~ msgid "" +#~ "Find useful options regarding the One Stop Shop procedure here." +#~ msgstr "" +#~ "Finde hier nützliche Optionen zum One Stop Shop Verfahren." + +#, php-format +#~ msgctxt "oss-tax-rate-import" +#~ msgid "VAT %s" +#~ msgstr "MwSt. %s" diff --git a/packages/one-stop-shop-woocommerce/i18n/languages/oss-woocommerce-de_DE_formal.mo b/packages/one-stop-shop-woocommerce/i18n/languages/oss-woocommerce-de_DE_formal.mo new file mode 100644 index 0000000000000000000000000000000000000000..18454f2972794a928661b2031b4791d30322b1a3 GIT binary patch literal 12859 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 HG-dR^A_MPt literal 0 HcmV?d00001 diff --git a/packages/one-stop-shop-woocommerce/i18n/languages/oss-woocommerce-de_DE_formal.po b/packages/one-stop-shop-woocommerce/i18n/languages/oss-woocommerce-de_DE_formal.po new file mode 100644 index 000000000..fa65c1941 --- /dev/null +++ b/packages/one-stop-shop-woocommerce/i18n/languages/oss-woocommerce-de_DE_formal.po @@ -0,0 +1,788 @@ +msgid "" +msgstr "" +"Project-Id-Version: One Stop Shop for WooCommerce\n" +"POT-Creation-Date: 2022-07-14 16:42+0200\n" +"PO-Revision-Date: 2022-07-14 16:43+0200\n" +"Last-Translator: Dennis Nissle \n" +"Language-Team: \n" +"Language: de_DE@formal\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 3.1\n" +"X-Poedit-Basepath: ../..\n" +"X-Poedit-Flags-xgettext: --add-comments=translators:\n" +"X-Poedit-WPHeader: one-stop-shop-woocommerce.php\n" +"X-Poedit-SourceCharset: UTF-8\n" +"X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;" +"esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;_n_noop:1,2;" +"_nx_noop:3c,1,2;__ngettext_noop:1,2\n" +"X-Poedit-SearchPath-0: .\n" +"X-Poedit-SearchPathExcluded-0: *.min.js\n" +"X-Poedit-SearchPathExcluded-1: vendor\n" +"X-Poedit-SearchPathExcluded-2: node_modules\n" +"X-Poedit-SearchPathExcluded-3: build\n" + +#: libs/woocommerce-eu-tax-helper/src/Helper.php:212 +msgid "Reduced rate" +msgstr "" + +#: libs/woocommerce-eu-tax-helper/src/Helper.php:213 +msgctxt "tax-helper-tax-class-name" +msgid "Greater reduced rate" +msgstr "Zusätzlicher reduzierter Preis" + +#: libs/woocommerce-eu-tax-helper/src/Helper.php:214 +msgctxt "tax-helper-tax-class-name" +msgid "Super reduced rate" +msgstr "Stark reduzierter Preis" + +#: libs/woocommerce-eu-tax-helper/src/Helper.php:617 +msgctxt "tax-helper" +msgid "Madeira" +msgstr "Madeira" + +#: libs/woocommerce-eu-tax-helper/src/Helper.php:624 +msgctxt "tax-helper" +msgid "Acores" +msgstr "Azoren" + +#: libs/woocommerce-eu-tax-helper/src/Helper.php:660 +msgctxt "tax-helper" +msgid "Northern Ireland" +msgstr "Nordirland" + +#: libs/woocommerce-eu-tax-helper/src/Helper.php:673 +msgctxt "tax-helper-rate-import" +msgid "Exempt" +msgstr "Ausnahme" + +#: libs/woocommerce-eu-tax-helper/src/Helper.php:742 +#, php-format +msgctxt "tax-helper-rate-import" +msgid "VAT %1$s %% %2$s" +msgstr "MwSt. %1$s %% %2$s" + +#. translators: 1: composer command. 2: plugin directory +#: one-stop-shop-woocommerce.php:44 one-stop-shop-woocommerce.php:62 +#, php-format +msgctxt "oss" +msgid "" +"Your installation of the One Stop Shop feature plugin is incomplete. Please " +"run %1$s within the %2$s directory." +msgstr "" +"Ihre Installation des One Stop Shop Feature Plugins ist nicht komplett. " +"Bitte führen Sie %1$s innerhalb des %2$s Verzeichnisses aus." + +#: src/Admin.php:78 src/Admin.php:79 +msgctxt "oss" +msgid "Refresh VAT rates (OSS)" +msgstr "EU Steuersätze erneuern (OSS)" + +#: src/Admin.php:83 +msgctxt "oss" +msgid "Note:" +msgstr "Hinweis:" + +#: src/Admin.php:84 +#, php-format +msgctxt "oss" +msgid "" +"This option will delete all of your current EU VAT rates and re-import them " +"based on your current OSS status." +msgstr "" +"Diese Option löscht alle Ihre aktuellen EU Steuersätze und importiert sie " +"anschließend auf Basis Ihres OSS Status neu." + +#: src/Admin.php:214 +#, php-format +msgctxt "oss" +msgid "" +"Seems like you have reached (or are close to reaching) the delivery " +"threshold for the current year. Please make sure to check the report details and take action in case necessary." +msgstr "" +"Sie sind kurz davor oder haben bereits die Lieferschwelle für das aktuelle " +"Jahr überschritten. Bitte prüfen Sie die Details des Berichts und unternehmen Sie weitere Schritte." + +#: src/Admin.php:218 +msgctxt "oss" +msgid "Delivery threshold reached (OSS)" +msgstr "Lieferschwelle erreicht (OSS)" + +#: src/Admin.php:448 src/SettingsPage.php:17 +msgctxt "oss" +msgid "OSS" +msgstr "OSS" + +#: src/Admin.php:448 src/Admin.php:566 src/SettingsPage.php:23 +msgctxt "oss" +msgid "One Stop Shop" +msgstr "One Stop Shop" + +#: src/Admin.php:469 src/Package.php:365 +#, php-format +msgctxt "oss" +msgid "Q%1$s/%2$s" +msgstr "Q%1$s/%2$s" + +#: src/Admin.php:478 src/Package.php:370 +#, php-format +msgctxt "oss" +msgid "%1$s/%2$s" +msgstr "%1$s/%2$s" + +#: src/Admin.php:486 +msgctxt "oss" +msgid "New Report" +msgstr "Neuer Bericht" + +#: src/Admin.php:493 +msgctxt "oss" +msgid "Type" +msgstr "Typ" + +#: src/Admin.php:505 +msgctxt "oss" +msgid "Year" +msgstr "Jahr" + +#: src/Admin.php:517 +msgctxt "oss" +msgid "Quarter" +msgstr "Quartal" + +#: src/Admin.php:529 +msgctxt "oss" +msgid "Month" +msgstr "Monat" + +#: src/Admin.php:541 +msgctxt "oss" +msgid "Date range" +msgstr "Zeitraum" + +#: src/Admin.php:553 +msgctxt "oss" +msgid "Start report" +msgstr "Bericht starten" + +#: src/Admin.php:567 +msgctxt "oss" +msgid "New report" +msgstr "Neuer Bericht" + +#: src/Admin.php:609 +msgctxt "oss" +msgid "View" +msgstr "Ansehen" + +#: src/Admin.php:613 +msgctxt "oss" +msgid "Export" +msgstr "Exportieren" + +#: src/Admin.php:617 +msgctxt "oss" +msgid "Export BOP" +msgstr "BOP-CSV exportieren" + +#: src/Admin.php:621 +msgctxt "oss" +msgid "Refresh" +msgstr "Aktualisieren" + +#: src/Admin.php:625 +msgctxt "oss" +msgid "Delete" +msgstr "Löschen" + +#: src/Admin.php:631 +msgctxt "oss" +msgid "Cancel" +msgstr "Abbrechen" + +#: src/Admin.php:669 +msgctxt "oss" +msgid "Country" +msgstr "Land" + +#: src/Admin.php:670 +msgctxt "oss" +msgid "Tax Rate" +msgstr "Steuersatz" + +#: src/Admin.php:671 +msgctxt "oss" +msgid "Net Total" +msgstr "Nettobetrag" + +#: src/Admin.php:672 +msgctxt "oss" +msgid "Tax Total" +msgstr "Steuerbertrag" + +#: src/Admin.php:703 +#, php-format +msgctxt "oss" +msgid "%1$s %%" +msgstr "%1$s %%" + +#: src/Admin.php:716 +#, php-format +msgctxt "oss" +msgid "" +"Currently processed %1$s orders. Next iteration is scheduled for %2$s. Find pending actions" +msgstr "" +"Aktuell %1$s Bestellung verarbeitet. Nächster Durchlauf planmäßig am %2$s. " +"Offene Aktionen finden" + +#: src/Admin.php:716 +msgctxt "oss" +msgid "Not yet known" +msgstr "Noch nicht bekannt" + +#: src/Admin.php:747 src/ReportTable.php:39 src/SettingsPage.php:23 +msgctxt "oss" +msgid "Reports" +msgstr "Berichte" + +#: src/AdminNote.php:46 +msgctxt "oss" +msgid "Dismiss" +msgstr "Ausblenden" + +#: src/AsyncReportGenerator.php:258 +msgctxt "oss" +msgid "No orders found." +msgstr "Keine Bestellungen gefunden." + +#: src/CSVExporter.php:54 +msgctxt "oss" +msgid "Country code" +msgstr "Land des Verbrauchs" + +#: src/CSVExporter.php:55 +msgctxt "oss" +msgid "Tax rate" +msgstr "Umsatzsteuersatz" + +#: src/CSVExporter.php:56 +msgctxt "oss" +msgid "Taxable base" +msgstr "Nettobetrag" + +#: src/CSVExporter.php:57 +msgctxt "oss" +msgid "Amount" +msgstr "Umsatzsteuerbetrag" + +#: src/DeliveryThresholdEmailNotification.php:19 +msgctxt "oss" +msgid "OSS Delivery Threshold Notification" +msgstr "OSS Lieferschwelle Benachrichtigung" + +#: src/DeliveryThresholdEmailNotification.php:20 +msgctxt "oss" +msgid "" +"This email notifies shop owners in case the delivery threshold (OSS) is " +"close to being reached." +msgstr "" +"Diese E-Mail benachrichtigt den Shopbetreiber über eine in Kürze anstehende " +"Überschreitung der Lieferschwelle (OSS)." + +#: src/DeliveryThresholdEmailNotification.php:38 +msgctxt "oss" +msgid "[{site_title}]: OSS delivery threshold reached" +msgstr "[{site_title}]: OSS Lieferschwelle erreicht" + +#: src/DeliveryThresholdEmailNotification.php:48 +msgctxt "oss" +msgid "OSS delivery threshold reached" +msgstr "OSS Lieferschwelle erreicht" + +#: src/DeliveryThresholdWarning.php:14 +msgctxt "oss" +msgid "See details" +msgstr "Details ansehen" + +#: src/Package.php:178 +msgctxt "oss" +msgid "" +"To use the OSS for WooCommerce plugin please make sure that WooCommerce is " +"installed and activated." +msgstr "" +"Um das OSS für WooCommerce Plugin nutzen zu können muss WooCommerce " +"installiert und aktiviert sein." + +#: src/Package.php:350 src/ReportTable.php:40 +msgctxt "oss" +msgid "Report" +msgstr "Bericht" + +#: src/Package.php:374 +#, php-format +msgctxt "oss" +msgid "%1$s" +msgstr "%1$s" + +#: src/Package.php:379 +#, php-format +msgctxt "oss" +msgid "%1$s - %2$s" +msgstr "%1$s - %2$s" + +#: src/Package.php:384 +#, php-format +msgctxt "oss" +msgid "Observer %1$s" +msgstr "Beobachter %1$s" + +#: src/Package.php:626 +msgctxt "oss" +msgid "Quarterly" +msgstr "Quartalsweise" + +#: src/Package.php:627 +msgctxt "oss" +msgid "Yearly" +msgstr "Jährlich" + +#: src/Package.php:628 +msgctxt "oss" +msgid "Monthly" +msgstr "Monatlich" + +#: src/Package.php:629 +msgctxt "oss" +msgid "Custom" +msgstr "Individuell" + +#: src/Package.php:633 +msgctxt "oss" +msgid "Observer" +msgstr "Beobachter" + +#: src/Package.php:647 +msgctxt "oss" +msgid "Pending" +msgstr "In Bearbeitung" + +#: src/Package.php:648 +msgctxt "oss" +msgid "Completed" +msgstr "Fertiggestellt" + +#: src/Package.php:649 +msgctxt "oss" +msgid "Failed" +msgstr "Fehlgeschlagen" + +#: src/ReportTable.php:124 +#, php-format +msgctxt "oss" +msgid "%d report deleted." +msgid_plural "%d reports deleted." +msgstr[0] "%d Bericht gelöscht." +msgstr[1] "%d Berichte gelöscht." + +#: src/ReportTable.php:187 +msgctxt "oss" +msgid "No reports found" +msgstr "Keine Berichte gefunden" + +#: src/ReportTable.php:228 +#, php-format +msgctxt "oss" +msgid "All (%s)" +msgid_plural "All (%s)" +msgstr[0] "Alle (%s)" +msgstr[1] "Alle (%s)" + +#: src/ReportTable.php:255 +#, php-format +msgctxt "oss" +msgid " (%s)" +msgid_plural " (%s)" +msgstr[0] " (%s)" +msgstr[1] " (%s)" + +#: src/ReportTable.php:326 +msgctxt "oss" +msgid "Filter" +msgstr "Filtern" + +#: src/ReportTable.php:353 +msgctxt "oss" +msgid "Title" +msgstr "Titel" + +#: src/ReportTable.php:354 +msgctxt "oss" +msgid "Start" +msgstr "Start" + +#: src/ReportTable.php:355 +msgctxt "oss" +msgid "End" +msgstr "Ende" + +#: src/ReportTable.php:356 templates/emails/admin-delivery-threshold.php:25 +msgctxt "oss" +msgid "Net total" +msgstr "Nettobetrag" + +#: src/ReportTable.php:357 templates/emails/admin-delivery-threshold.php:26 +msgctxt "oss" +msgid "Tax total" +msgstr "Steuerbertrag" + +#: src/ReportTable.php:358 +msgctxt "oss" +msgid "Status" +msgstr "Status" + +#: src/ReportTable.php:359 +msgctxt "oss" +msgid "Actions" +msgstr "Aktionen" + +#: src/ReportTable.php:423 +#, php-format +msgctxt "oss" +msgid "Select %s" +msgstr "%s auswählen" + +#: src/ReportTable.php:516 +msgctxt "oss" +msgid "Delete Permanently" +msgstr "Unwiderruflich löschen" + +#: src/Settings.php:16 +msgctxt "oss" +msgid "General" +msgstr "Allgemein" + +#: src/Settings.php:21 +msgctxt "oss" +msgid "" +"Find useful options regarding the One Stop Shop procedure here." +msgstr "" +"Finden Sie hier nützliche Optionen zum One Stop Shop Verfahren." + +#: src/Settings.php:38 +msgctxt "oss" +msgid "OSS status" +msgstr "OSS Status" + +#: src/Settings.php:39 +msgctxt "oss" +msgid "Yes, I'm currently participating in the OSS procedure." +msgstr "Ja, ich nehme aktuell am One Stop Shop Verfahren teil." + +#: src/Settings.php:46 +msgctxt "oss" +msgid "Observation" +msgstr "Überwachung" + +#: src/Settings.php:47 +msgctxt "oss" +msgid "Automatically observe the delivery threshold of the current year." +msgstr "Überwache die Lieferschwelle des aktuellen Jahres automatisch." + +#: src/Settings.php:47 +msgctxt "oss" +msgid "" +"This option will automatically calculate the amount applicable for the OSS " +"procedure delivery threshold once per day for the current year. The report " +"will only recalculated for the days which are not yet subject to the " +"observation to save processing time." +msgstr "" +"Diese Option überwacht automatisch die Lieferschwelle des OSS Verfahrens für " +"das aktuelle Jahr, indem der dazugehörige Bericht täglich erweitert und " +"nachberechnet wird. Der Bericht wird nur für die Tage nachberechnet, für die " +"aktuell noch keine Überwachung stattfindet." + +#: src/Settings.php:59 +msgctxt "oss" +msgid "Delivery threshold" +msgstr "Lieferschwelle" + +#: src/Settings.php:72 +msgctxt "oss" +msgid "Participation" +msgstr "Teilnahme" + +#: src/Settings.php:79 +msgctxt "oss" +msgid "Report Order Date" +msgstr "Bericht Bestelldatum" + +#: src/Settings.php:80 +msgctxt "oss" +msgid "" +"Select the relevant order date to be used to determine whether to include an " +"order in a report." +msgstr "" +"Wählen Sie das relevante Bestelldatum aus auf Basis dessen entschieden wird " +"ob eine Bestellung in einen Bericht inkludiert wird." + +#: src/Settings.php:85 +msgctxt "oss" +msgid "Date paid" +msgstr "Zahlungsdatum" + +#: src/Settings.php:86 +msgctxt "oss" +msgid "Date created" +msgstr "Erstellungsdatum" + +#: src/Settings.php:97 +msgctxt "oss" +msgid "Fixed gross prices" +msgstr "Feste Bruttopreise" + +#: src/Settings.php:98 +msgctxt "oss" +msgid "Apply the same gross price regardless of the tax rate for EU countries." +msgstr "Verwende den Bruttopreis für EU-Länder unabhängig vom Steuersatz." + +#: src/Settings.php:98 +msgctxt "oss" +msgid "" +"This option will make sure that your customers pay the same price no matter " +"the tax rate (based on the country chosen) to be applied." +msgstr "" +"Diese Option bewirkt, dass Kunden, unabhängig vom Land und damit vom " +"Steuersatz den selben Bruttopreis bezahlen." + +#: src/Settings.php:104 +msgctxt "oss" +msgid "Third countries" +msgstr "Drittländer" + +#: src/Settings.php:105 +msgctxt "oss" +msgid "Apply the same gross price for third countries too." +msgstr "Verwende den Bruttopreis auch für Drittländer." + +#: src/Settings.php:138 src/Settings.php:139 +msgctxt "oss" +msgid "Are you sure? Please backup your tax rates before proceeding." +msgstr "" +"Sind Sie sicher? Bitte erstellen Sie vorab ein Backup Ihrer Steuersätze." + +#: src/Settings.php:138 +msgctxt "oss" +msgid "End OSS participation" +msgstr "OSS Teilnahme beenden" + +#: src/Settings.php:138 +msgctxt "oss" +msgid "Start OSS participation" +msgstr "OSS Teilnahme starten" + +#: src/Settings.php:139 +msgctxt "oss" +msgid "refresh VAT rates" +msgstr "Steuersätze erneuern" + +#: src/Settings.php:140 +msgctxt "oss" +msgid "learn more" +msgstr "Mehr erfahren" + +#: src/Settings.php:142 +msgctxt "oss" +msgid "" +"Use this option to automatically adjust tax-related options in WooCommerce. " +"Warning: This option will delete your current tax rates and add new tax " +"rates based on your OSS participation status." +msgstr "" +"Nutzen Sie diese Option um Ihre Steuereinstellungen in WooCommerce " +"automatisch anpassen zu lassen. Achtung: Diese Option löscht Ihre aktuellen " +"Steuersätze und fügt neue Steuersätze basierend auf Ihrem OSS Status hinzu." + +#: src/Settings.php:174 +msgctxt "oss" +msgid "See status" +msgstr "Status ansehen" + +#: src/Settings.php:174 +msgctxt "oss" +msgid "Start initial report" +msgstr "Initialen Bericht erstellen" + +#: src/Settings.php:175 +#, php-format +msgctxt "oss" +msgid "Report not yet completed. %s" +msgstr "Bericht noch nicht abgeschlossen. %s" + +#: src/Settings.php:175 +#, php-format +msgctxt "oss" +msgid "Report not yet started. %s" +msgstr "Bericht noch nicht gestartet. %s" + +#: src/Settings.php:193 +msgctxt "oss-amounts" +msgid "of" +msgstr "von" + +#: src/Settings.php:193 +#, php-format +msgctxt "oss" +msgid "As of: %s" +msgstr "Stand: %s" + +#: src/Settings.php:193 +msgctxt "oss" +msgid "see details" +msgstr "Details ansehen" + +#: src/Settings.php:194 +#, php-format +msgctxt "oss" +msgid "" +"This value indicates your current net total amount applicable for the One " +"Stop Shop procedure delivery threshold of the current year. You should take " +"action in case the delivery threshold is or is close to being exceeded. Find out more about the calculation." +msgstr "" +"Dieser Wert entspricht der Bemessungsgrundlage (Nettobetrag) des aktuellen " +"Jahres für die Lieferschwelle des One Stop Shop Verfahrens. Sie sollten " +"tätig werden, wenn die Lieferschwelle kurz vor einer Überschreitung steht " +"oder bereits überschritten wurde. Erfahren Sie mehr über " +"die Berechnung." + +#: src/SettingsPage.php:23 +msgctxt "oss" +msgid "Learn More" +msgstr "Mehr erfahren" + +#: src/Tax.php:260 src/Tax.php:338 +#, php-format +msgctxt "oss" +msgid "Tax class (%s)" +msgstr "Steuerklasse (%s)" + +#: src/Tax.php:261 +msgctxt "oss" +msgid "Same as parent" +msgstr "Gleiche wie übergeordnet" + +#: src/Tax.php:263 src/Tax.php:296 src/Tax.php:340 src/Tax.php:374 +msgctxt "oss" +msgid "remove" +msgstr "Löschen" + +#: src/Tax.php:273 src/Tax.php:351 +msgctxt "oss" +msgid "Add country specific tax class (OSS)" +msgstr "Länderspezifische Steuerklasse hinzufügen (OSS)" + +#: src/Tax.php:280 src/Tax.php:358 +msgctxt "oss" +msgid "Select country" +msgstr "Land auswählen" + +#: src/Tax.php:305 src/Tax.php:315 +msgctxt "oss" +msgid "EU-wide" +msgstr "EU-weit" + +#. translators: %s: Customer billing full name +#: templates/emails/admin-delivery-threshold.php:19 +#, php-format +msgctxt "oss" +msgid "" +"Your OSS delivery threshold of %1$s has been reached. Please take action " +"immediately. Visit the OSS Settings Panel for details." +msgstr "" +"Ihre OSS Lieferschwelle von %1$s wurde erreicht. Bitte werden Sie umgehend " +"tätig. Besuchen Sie die OSS Einstellungen um Details zu " +"erfahren." + +#: templates/emails/admin-delivery-threshold.php:21 +msgctxt "oss" +msgid "Report Details" +msgstr "Details des Berichts" + +#: templates/emails/admin-delivery-threshold.php:24 +msgctxt "oss" +msgid "Period" +msgstr "Periode" + +#: templates/emails/admin-delivery-threshold.php:29 +msgctxt "oss" +msgid "See report details" +msgstr "Details des Berichts abrufen" + +#: templates/emails/plain/admin-delivery-threshold.php:17 +#, php-format +msgctxt "oss" +msgid "" +"Your OSS delivery threshold of %1$s has been reached. Please take action " +"immediately. Visit the OSS Settings Panel (%2$s) for details." +msgstr "" +"Ihre OSS Lieferschwelle von %1$s wurde erreicht. Bitte werden Sie umgehend " +"tätig. Besuchen Sie die OSS Einstellungen (%2$s) um Details zu erfahren." + +#. Plugin Name of the plugin/theme +msgid "One Stop Shop for WooCommerce" +msgstr "One Stop Shop für WooCommerce" + +#. Plugin URI of the plugin/theme +msgid "https://github.com/vendidero/one-stop-shop-woocommerce" +msgstr "https://github.com/vendidero/one-stop-shop-woocommerce" + +#. Description of the plugin/theme +msgid "Comply with the One Stop Shop procedure while using WooCommerce." +msgstr "Nutzen Sie das One Stop Shop Verfahren zusammen mit WooCommerce." + +#. Author of the plugin/theme +msgid "vendidero" +msgstr "vendidero" + +#. Author URI of the plugin/theme +msgid "https://vendidero.de" +msgstr "https://vendidero.de" + +#~ msgctxt "storeabill-core" +#~ msgid "Year" +#~ msgstr "Jahr" + +#~ msgctxt "storeabill-core" +#~ msgid "Quarter" +#~ msgstr "Quartal" + +#~ msgctxt "storeabill-core" +#~ msgid "Month" +#~ msgstr "Monat" + +#~ msgctxt "storeabill-core" +#~ msgid "Date range" +#~ msgstr "Zeitraum" + +#~ msgctxt "oss" +#~ msgid "" +#~ "Find useful options regarding the One Stop Shop procedure here." +#~ msgstr "" +#~ "Finden Sie hier nützliche Optionen zum One Stop Shop Verfahren." + +#, php-format +#~ msgctxt "oss-tax-rate-import" +#~ msgid "VAT %s" +#~ msgstr "MwSt. %s" diff --git a/packages/one-stop-shop-woocommerce/i18n/languages/oss-woocommerce.pot b/packages/one-stop-shop-woocommerce/i18n/languages/oss-woocommerce.pot new file mode 100644 index 000000000..bc7292f91 --- /dev/null +++ b/packages/one-stop-shop-woocommerce/i18n/languages/oss-woocommerce.pot @@ -0,0 +1,673 @@ +#, fuzzy +msgid "" +msgstr "" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" +"Project-Id-Version: One Stop Shop for WooCommerce\n" +"POT-Creation-Date: 2021-07-08 13:56+0200\n" +"PO-Revision-Date: 2021-05-10 09:48+0200\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 2.4.3\n" +"X-Poedit-Basepath: ../..\n" +"X-Poedit-Flags-xgettext: --add-comments=translators:\n" +"X-Poedit-WPHeader: one-stop-shop-woocommerce.php\n" +"X-Poedit-SourceCharset: UTF-8\n" +"X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;" +"esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;_n_noop:1,2;" +"_nx_noop:3c,1,2;__ngettext_noop:1,2\n" +"X-Poedit-SearchPath-0: .\n" +"X-Poedit-SearchPathExcluded-0: *.min.js\n" +"X-Poedit-SearchPathExcluded-1: vendor\n" +"X-Poedit-SearchPathExcluded-2: node_modules\n" +"X-Poedit-SearchPathExcluded-3: build\n" + +#. translators: 1: composer command. 2: plugin directory +#: one-stop-shop-woocommerce.php:44 one-stop-shop-woocommerce.php:62 +#, php-format +msgctxt "oss" +msgid "" +"Your installation of the One Stop Shop feature plugin is incomplete. Please " +"run %1$s within the %2$s directory." +msgstr "" + +#: src/Admin.php:76 src/Admin.php:77 +msgctxt "oss" +msgid "Refresh VAT rates (OSS)" +msgstr "" + +#: src/Admin.php:81 +msgctxt "oss" +msgid "Note:" +msgstr "" + +#: src/Admin.php:82 +#, php-format +msgctxt "oss" +msgid "" +"This option will delete all of your current EU VAT rates and re-import them " +"based on your current OSS status." +msgstr "" + +#: src/Admin.php:212 +#, php-format +msgctxt "oss" +msgid "" +"Seems like you have reached (or are close to reaching) the delivery " +"threshold for the current year. Please make sure to check the report details and take action in case necessary." +msgstr "" + +#: src/Admin.php:216 +msgctxt "oss" +msgid "Delivery threshold reached (OSS)" +msgstr "" + +#: src/Admin.php:432 src/SettingsPage.php:17 +msgctxt "oss" +msgid "OSS" +msgstr "" + +#: src/Admin.php:432 src/Admin.php:550 src/SettingsPage.php:23 +msgctxt "oss" +msgid "One Stop Shop" +msgstr "" + +#: src/Admin.php:453 src/Package.php:264 +#, php-format +msgctxt "oss" +msgid "Q%1$s/%2$s" +msgstr "" + +#: src/Admin.php:462 src/Package.php:269 +#, php-format +msgctxt "oss" +msgid "%1$s/%2$s" +msgstr "" + +#: src/Admin.php:470 +msgctxt "oss" +msgid "New Report" +msgstr "" + +#: src/Admin.php:477 +msgctxt "oss" +msgid "Type" +msgstr "" + +#: src/Admin.php:489 +msgctxt "oss" +msgid "Year" +msgstr "" + +#: src/Admin.php:501 +msgctxt "oss" +msgid "Quarter" +msgstr "" + +#: src/Admin.php:513 +msgctxt "oss" +msgid "Month" +msgstr "" + +#: src/Admin.php:525 +msgctxt "oss" +msgid "Date range" +msgstr "" + +#: src/Admin.php:537 +msgctxt "oss" +msgid "Start report" +msgstr "" + +#: src/Admin.php:551 +msgctxt "oss" +msgid "New report" +msgstr "" + +#: src/Admin.php:593 +msgctxt "oss" +msgid "View" +msgstr "" + +#: src/Admin.php:597 +msgctxt "oss" +msgid "Export" +msgstr "" + +#: src/Admin.php:601 +msgctxt "oss" +msgid "Refresh" +msgstr "" + +#: src/Admin.php:605 +msgctxt "oss" +msgid "Delete" +msgstr "" + +#: src/Admin.php:611 +msgctxt "oss" +msgid "Cancel" +msgstr "" + +#: src/Admin.php:640 +msgctxt "oss" +msgid "Country" +msgstr "" + +#: src/Admin.php:641 +msgctxt "oss" +msgid "Tax Rate" +msgstr "" + +#: src/Admin.php:642 +msgctxt "oss" +msgid "Net Total" +msgstr "" + +#: src/Admin.php:643 +msgctxt "oss" +msgid "Tax Total" +msgstr "" + +#: src/Admin.php:674 +#, php-format +msgctxt "oss" +msgid "%1$s %%" +msgstr "" + +#: src/Admin.php:686 +#, php-format +msgctxt "oss" +msgid "" +"Currently processed %1$s orders. Next iteration is scheduled for %2$s. Find pending actions" +msgstr "" + +#: src/Admin.php:686 +msgctxt "oss" +msgid "Not yet known" +msgstr "" + +#: src/Admin.php:717 src/ReportTable.php:39 src/SettingsPage.php:23 +msgctxt "oss" +msgid "Reports" +msgstr "" + +#: src/AdminNote.php:39 +msgctxt "oss" +msgid "Dismiss" +msgstr "" + +#: src/AsyncReportGenerator.php:244 +msgctxt "oss" +msgid "No orders found." +msgstr "" + +#: src/CSVExporter.php:52 +msgctxt "oss" +msgid "Country code" +msgstr "" + +#: src/CSVExporter.php:53 +msgctxt "oss" +msgid "Tax rate" +msgstr "" + +#: src/CSVExporter.php:54 +msgctxt "oss" +msgid "Taxable base" +msgstr "" + +#: src/CSVExporter.php:55 +msgctxt "oss" +msgid "Amount" +msgstr "" + +#: src/DeliveryThresholdEmailNotification.php:19 +msgctxt "oss" +msgid "OSS Delivery Threshold Notification" +msgstr "" + +#: src/DeliveryThresholdEmailNotification.php:20 +msgctxt "oss" +msgid "" +"This email notifies shop owners in case the delivery threshold (OSS) is " +"close to being reached." +msgstr "" + +#: src/DeliveryThresholdEmailNotification.php:38 +msgctxt "oss" +msgid "[{site_title}]: OSS delivery threshold reached" +msgstr "" + +#: src/DeliveryThresholdEmailNotification.php:48 +msgctxt "oss" +msgid "OSS delivery threshold reached" +msgstr "" + +#: src/DeliveryThresholdWarning.php:13 +msgctxt "oss" +msgid "See details" +msgstr "" + +#: src/Package.php:80 +msgctxt "oss" +msgid "" +"To use the OSS for WooCommerce plugin please make sure that WooCommerce is " +"installed and activated." +msgstr "" + +#: src/Package.php:249 src/ReportTable.php:40 +msgctxt "oss" +msgid "Report" +msgstr "" + +#: src/Package.php:273 +#, php-format +msgctxt "oss" +msgid "%1$s" +msgstr "" + +#: src/Package.php:278 +#, php-format +msgctxt "oss" +msgid "%1$s - %2$s" +msgstr "" + +#: src/Package.php:283 +#, php-format +msgctxt "oss" +msgid "Observer %1$s" +msgstr "" + +#: src/Package.php:482 +msgctxt "oss" +msgid "Quarterly" +msgstr "" + +#: src/Package.php:483 +msgctxt "oss" +msgid "Yearly" +msgstr "" + +#: src/Package.php:484 +msgctxt "oss" +msgid "Monthly" +msgstr "" + +#: src/Package.php:485 +msgctxt "oss" +msgid "Custom" +msgstr "" + +#: src/Package.php:489 +msgctxt "oss" +msgid "Observer" +msgstr "" + +#: src/Package.php:503 +msgctxt "oss" +msgid "Pending" +msgstr "" + +#: src/Package.php:504 +msgctxt "oss" +msgid "Completed" +msgstr "" + +#: src/Package.php:505 +msgctxt "oss" +msgid "Failed" +msgstr "" + +#: src/ReportTable.php:121 +#, php-format +msgctxt "oss" +msgid "%d report deleted." +msgid_plural "%d reports deleted." +msgstr[0] "" +msgstr[1] "" + +#: src/ReportTable.php:184 +msgctxt "oss" +msgid "No reports found" +msgstr "" + +#: src/ReportTable.php:225 +#, php-format +msgctxt "oss" +msgid "All (%s)" +msgid_plural "All (%s)" +msgstr[0] "" +msgstr[1] "" + +#: src/ReportTable.php:250 +#, php-format +msgctxt "oss" +msgid " (%s)" +msgid_plural " (%s)" +msgstr[0] "" +msgstr[1] "" + +#: src/ReportTable.php:323 +msgctxt "oss" +msgid "Filter" +msgstr "" + +#: src/ReportTable.php:350 +msgctxt "oss" +msgid "Title" +msgstr "" + +#: src/ReportTable.php:351 +msgctxt "oss" +msgid "Start" +msgstr "" + +#: src/ReportTable.php:352 +msgctxt "oss" +msgid "End" +msgstr "" + +#: src/ReportTable.php:353 templates/emails/admin-delivery-threshold.php:25 +msgctxt "oss" +msgid "Net total" +msgstr "" + +#: src/ReportTable.php:354 templates/emails/admin-delivery-threshold.php:26 +msgctxt "oss" +msgid "Tax total" +msgstr "" + +#: src/ReportTable.php:355 +msgctxt "oss" +msgid "Status" +msgstr "" + +#: src/ReportTable.php:356 +msgctxt "oss" +msgid "Actions" +msgstr "" + +#: src/ReportTable.php:420 +#, php-format +msgctxt "oss" +msgid "Select %s" +msgstr "" + +#: src/ReportTable.php:513 +msgctxt "oss" +msgid "Delete Permanently" +msgstr "" + +#: src/Settings.php:14 +msgctxt "oss" +msgid "General" +msgstr "" + +#: src/Settings.php:19 +msgctxt "oss" +msgid "" +"Find useful options regarding the One Stop Shop procedure here." +msgstr "" + +#: src/Settings.php:31 +msgctxt "oss" +msgid "OSS status" +msgstr "" + +#: src/Settings.php:32 +msgctxt "oss" +msgid "Yes, I'm currently participating in the OSS procedure." +msgstr "" + +#: src/Settings.php:39 +msgctxt "oss" +msgid "Observation" +msgstr "" + +#: src/Settings.php:40 +msgctxt "oss" +msgid "Automatically observe the delivery threshold of the current year." +msgstr "" + +#: src/Settings.php:40 +msgctxt "oss" +msgid "" +"This option will automatically calculate the amount applicable for the OSS " +"procedure delivery threshold once per day for the current year. The report " +"will only recalculated for the days which are not yet subject to the " +"observation to save processing time." +msgstr "" + +#: src/Settings.php:50 +msgctxt "oss" +msgid "Delivery threshold" +msgstr "" + +#: src/Settings.php:60 +msgctxt "oss" +msgid "Participation" +msgstr "" + +#: src/Settings.php:70 +msgctxt "oss" +msgid "Fixed gross prices" +msgstr "" + +#: src/Settings.php:71 +msgctxt "oss" +msgid "Apply the same gross price regardless of the tax rate." +msgstr "" + +#: src/Settings.php:71 +msgctxt "oss" +msgid "" +"This option will make sure that your customers pay the same price no matter " +"the tax rate (based on the country chosen) to be applied." +msgstr "" + +#: src/Settings.php:92 +msgctxt "oss" +msgid "Are you sure? Please backup your tax rates before proceeding." +msgstr "" + +#: src/Settings.php:92 +msgctxt "oss" +msgid "End OSS participation" +msgstr "" + +#: src/Settings.php:92 +msgctxt "oss" +msgid "Start OSS participation" +msgstr "" + +#: src/Settings.php:93 +msgctxt "oss" +msgid "learn more" +msgstr "" + +#: src/Settings.php:95 +msgctxt "oss" +msgid "" +"Use this option to automatically adjust tax-related options in WooCommerce. " +"Warning: This option will delete your current tax rates and add new tax " +"rates based on your OSS participation status." +msgstr "" + +#: src/Settings.php:127 +msgctxt "oss" +msgid "See status" +msgstr "" + +#: src/Settings.php:127 +msgctxt "oss" +msgid "Start initial report" +msgstr "" + +#: src/Settings.php:128 +#, php-format +msgctxt "oss" +msgid "Report not yet completed. %s" +msgstr "" + +#: src/Settings.php:128 +#, php-format +msgctxt "oss" +msgid "Report not yet started. %s" +msgstr "" + +#: src/Settings.php:146 +msgctxt "oss-amounts" +msgid "of" +msgstr "" + +#: src/Settings.php:146 +#, php-format +msgctxt "oss" +msgid "As of: %s" +msgstr "" + +#: src/Settings.php:146 +msgctxt "oss" +msgid "see details" +msgstr "" + +#: src/Settings.php:147 +#, php-format +msgctxt "oss" +msgid "" +"This value indicates your current net total amount applicable for the One " +"Stop Shop procedure delivery threshold of the current year. You should take " +"action in case the delivery threshold is or is close to being exceeded. Find out more about the calculation." +msgstr "" + +#: src/SettingsPage.php:23 +msgctxt "oss" +msgid "Learn More" +msgstr "" + +#: src/Tax.php:278 src/Tax.php:336 +#, php-format +msgctxt "oss" +msgid "Tax class (%s)" +msgstr "" + +#: src/Tax.php:279 +msgctxt "oss" +msgid "Same as parent" +msgstr "" + +#: src/Tax.php:281 src/Tax.php:314 src/Tax.php:338 src/Tax.php:372 +msgctxt "oss" +msgid "remove" +msgstr "" + +#: src/Tax.php:291 src/Tax.php:349 +msgctxt "oss" +msgid "Add country specific tax class (OSS)" +msgstr "" + +#: src/Tax.php:298 src/Tax.php:356 +msgctxt "oss" +msgid "Select country" +msgstr "" + +#. translators: Do not translate +#: src/Tax.php:452 src/Tax.php:579 +msgid "Reduced rate" +msgstr "" + +#: src/Tax.php:455 src/Tax.php:571 +msgctxt "oss" +msgid "Greater reduced rate" +msgstr "" + +#: src/Tax.php:458 src/Tax.php:575 +msgctxt "oss" +msgid "Super reduced rate" +msgstr "" + +#: src/Tax.php:751 +msgctxt "oss" +msgid "Madeira" +msgstr "" + +#: src/Tax.php:758 +msgctxt "oss" +msgid "Acores" +msgstr "" + +#: src/Tax.php:794 +msgctxt "oss" +msgid "Northern Ireland" +msgstr "" + +#: src/Tax.php:807 +msgctxt "oss-tax-rate-import" +msgid "Exempt" +msgstr "" + +#: src/Tax.php:873 +#, php-format +msgctxt "oss-tax-rate-import" +msgid "VAT %1$s %% %2$s" +msgstr "" + +#. translators: %s: Customer billing full name +#: templates/emails/admin-delivery-threshold.php:19 +#, php-format +msgctxt "oss" +msgid "" +"Your OSS delivery threshold of %1$s has been reached. Please take action " +"immediately. Visit the OSS Settings Panel for details." +msgstr "" + +#: templates/emails/admin-delivery-threshold.php:21 +msgctxt "oss" +msgid "Report Details" +msgstr "" + +#: templates/emails/admin-delivery-threshold.php:24 +msgctxt "oss" +msgid "Period" +msgstr "" + +#: templates/emails/admin-delivery-threshold.php:29 +msgctxt "oss" +msgid "See report details" +msgstr "" + +#: templates/emails/plain/admin-delivery-threshold.php:17 +#, php-format +msgctxt "oss" +msgid "" +"Your OSS delivery threshold of %1$s has been reached. Please take action " +"immediately. Visit the OSS Settings Panel (%2$s) for details." +msgstr "" + +#. Plugin Name of the plugin/theme +msgid "One Stop Shop for WooCommerce" +msgstr "" + +#. Plugin URI of the plugin/theme +msgid "https://github.com/vendidero/one-stop-shop-woocommerce" +msgstr "" + +#. Description of the plugin/theme +msgid "Comply with the One Stop Shop procedure while using WooCommerce." +msgstr "" + +#. Author of the plugin/theme +msgid "vendidero" +msgstr "" + +#. Author URI of the plugin/theme +msgid "https://vendidero.de" +msgstr "" diff --git a/packages/one-stop-shop-woocommerce/libs/woocommerce-eu-tax-helper/src/Helper.php b/packages/one-stop-shop-woocommerce/libs/woocommerce-eu-tax-helper/src/Helper.php new file mode 100644 index 000000000..bc9d680ba --- /dev/null +++ b/packages/one-stop-shop-woocommerce/libs/woocommerce-eu-tax-helper/src/Helper.php @@ -0,0 +1,911 @@ +countries->get_european_union_countries(); + + return $countries; + } + + public static function get_eu_vat_countries() { + return apply_filters( 'woocommerce_eu_tax_helper_eu_vat_countries', WC()->countries->get_european_union_countries( 'eu_vat' ) ); + } + + public static function is_northern_ireland( $country, $postcode = '' ) { + if ( 'GB' === $country && 'BT' === strtoupper( substr( trim( $postcode ), 0, 2 ) ) ) { + return true; + } elseif ( 'IX' === $country ) { + return true; + } + + return false; + } + + public static function is_eu_vat_country( $country, $postcode = '' ) { + $country = wc_strtoupper( $country ); + $postcode = wc_normalize_postcode( $postcode ); + $is_eu_vat_country = in_array( $country, self::get_eu_vat_countries(), true ); + + if ( self::is_northern_ireland( $country, $postcode ) ) { + $is_eu_vat_country = true; + } elseif ( self::is_eu_vat_postcode_exemption( $country, $postcode ) ) { + $is_eu_vat_country = false; + } + + return apply_filters( 'woocommerce_eu_tax_helper_is_eu_vat_country', $is_eu_vat_country, $country, $postcode ); + } + + public static function is_third_country( $country, $postcode = '' ) { + $is_third_country = true; + + /** + * In case the base country is within EU consider all non-EU VAT countries as third countries. + * In any other case consider every non-base-country as third country. + */ + if ( in_array( self::get_base_country(), self::get_eu_vat_countries(), true ) ) { + $is_third_country = ! self::is_eu_vat_country( $country, $postcode ); + } else { + $is_third_country = self::get_base_country() !== $country; + } + + return apply_filters( 'woocommerce_eu_tax_helper_is_third_country', $is_third_country, $country, $postcode ); + } + + public static function is_eu_country( $country ) { + return in_array( $country, self::get_eu_countries(), true ); + } + + public static function is_eu_vat_postcode_exemption( $country, $postcode = '' ) { + $country = wc_strtoupper( $country ); + $postcode = wc_normalize_postcode( $postcode ); + $exemptions = self::get_vat_postcode_exemptions_by_country(); + $is_exempt = false; + + if ( ! empty( $postcode ) && in_array( $country, self::get_eu_vat_countries(), true ) ) { + if ( array_key_exists( $country, $exemptions ) ) { + $wildcards = wc_get_wildcard_postcodes( $postcode, $country ); + + foreach ( $exemptions[ $country ] as $exempt_postcode ) { + if ( in_array( $exempt_postcode, $wildcards, true ) ) { + $is_exempt = true; + break; + } + } + } + } + + return $is_exempt; + } + + /** + * Get VAT exemptions (of EU countries) for certain postcodes (e.g. canary islands) + * + * @see https://www.hk24.de/produktmarken/beratung-service/recht-und-steuern/steuerrecht/umsatzsteuer-mehrwertsteuer/umsatzsteuer-mehrwertsteuer-international/verfahrensrecht/territoriale-besonderheiten-umsatzsteuer-zollrecht-1167674 + * @see https://github.com/woocommerce/woocommerce/issues/5143 + * @see https://ec.europa.eu/taxation_customs/business/vat/eu-vat-rules-topic/territorial-status-eu-countries-certain-territories_en + * + * @return \string[][] + */ + public static function get_vat_postcode_exemptions_by_country( $country = '' ) { + $country = wc_strtoupper( $country ); + + $exemptions = array( + 'DE' => array( + '27498', // Helgoland + '78266', // Büsingen am Hochrhein + ), + 'ES' => array( + '35*', // Canary Islands + '38*', // Canary Islands + '51*', // Ceuta + '52*', // Melilla + ), + 'GR' => array( + '63086', // Mount Athos + '63087', // Mount Athos + ), + 'FR' => array( + '971*', // Guadeloupe + '972*', // Martinique + '973*', // French Guiana + '974*', // Réunion + '976*', // Mayotte + ), + 'IT' => array( + '22060', // Livigno, Campione d’Italia + '23030', // Lake Lugano + ), + 'FI' => array( + '22*', // Aland islands + ), + ); + + if ( empty( $country ) ) { + return $exemptions; + } elseif ( array_key_exists( $country, $exemptions ) ) { + return $exemptions[ $country ]; + } else { + return array(); + } + } + + /** + * @param integer|\WC_Order $order + * + * @return array + */ + public static function get_order_taxable_location( $order ) { + $order = is_a( $order, 'WC_Order' ) ? $order : wc_get_order( $order ); + + $taxable_address = array( + WC()->countries->get_base_country(), + WC()->countries->get_base_state(), + WC()->countries->get_base_postcode(), + WC()->countries->get_base_city(), + ); + + if ( ! $order ) { + return $taxable_address; + } + + $tax_based_on = get_option( 'woocommerce_tax_based_on' ); + + if ( is_a( $order, 'WC_Order_Refund' ) ) { + $order = wc_get_order( $order->get_parent_id() ); + + if ( ! $order ) { + return $taxable_address; + } + } + + /** + * Shipping address data does not exist + */ + if ( 'shipping' === $tax_based_on && ! $order->get_shipping_country() ) { + $tax_based_on = 'billing'; + } + + $is_vat_exempt = apply_filters( 'woocommerce_order_is_vat_exempt', 'yes' === $order->get_meta( 'is_vat_exempt' ), $order ); + + /** + * In case the order is a VAT exempt, calculate net prices based on taxes from base country. + */ + if ( $is_vat_exempt ) { + $tax_based_on = 'base'; + } + + $country = 'shipping' === $tax_based_on ? $order->get_shipping_country() : $order->get_billing_country(); + + if ( 'base' !== $tax_based_on && ! empty( $country ) ) { + $taxable_address = array( + $country, + 'billing' === $tax_based_on ? $order->get_billing_state() : $order->get_shipping_state(), + 'billing' === $tax_based_on ? $order->get_billing_postcode() : $order->get_shipping_postcode(), + 'billing' === $tax_based_on ? $order->get_billing_city() : $order->get_shipping_city(), + ); + } + + return $taxable_address; + } + + public static function get_taxable_location() { + $is_admin_order_request = self::is_admin_order_request(); + + if ( $is_admin_order_request ) { + $taxable_address = array( + WC()->countries->get_base_country(), + WC()->countries->get_base_state(), + WC()->countries->get_base_postcode(), + WC()->countries->get_base_city(), + ); + + if ( isset( $_POST['order_id'] ) && ( $order = wc_get_order( absint( $_POST['order_id'] ) ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing + $taxable_address = self::get_order_taxable_location( $order ); + } + + return $taxable_address; + } else { + return \WC_Tax::get_tax_location(); + } + } + + public static function is_admin_order_ajax_request() { + $order_actions = array( 'woocommerce_calc_line_taxes', 'woocommerce_save_order_items', 'add_coupon_discount', 'refund_line_items', 'delete_refund' ); + + return isset( $_POST['action'], $_POST['order_id'] ) && ( strstr( wc_clean( wp_unslash( $_POST['action'] ) ), '_order_' ) || in_array( wc_clean( wp_unslash( $_POST['action'] ) ), $order_actions, true ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing + } + + public static function is_admin_order_request() { + return is_admin() && current_user_can( 'edit_shop_orders' ) && self::is_admin_order_ajax_request(); + } + + public static function current_request_has_vat_exempt() { + $is_admin_order_request = self::is_admin_order_request(); + $is_vat_exempt = false; + + if ( $is_admin_order_request ) { + if ( $order = wc_get_order( absint( $_POST['order_id'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.ValidatedSanitizedInput.InputNotValidated + $is_vat_exempt = apply_filters( 'woocommerce_order_is_vat_exempt', 'yes' === $order->get_meta( 'is_vat_exempt' ), $order ); + } + } else { + if ( WC()->customer && WC()->customer->is_vat_exempt() ) { + $is_vat_exempt = true; + } + } + + return $is_vat_exempt; + } + + public static function get_base_country() { + if ( WC()->countries ) { + return WC()->countries->get_base_country(); + } else { + return wc_get_base_location()['country']; + } + } + + /** + * Returns a list of EU countries except base country. + * + * @return string[] + */ + public static function get_non_base_eu_countries( $include_gb = false ) { + $countries = WC()->countries->get_european_union_countries( 'eu_vat' ); + + /** + * Include GB to allow Northern Ireland + */ + if ( $include_gb && ! in_array( 'GB', $countries, true ) ) { + $countries = array_merge( $countries, array( 'GB' ) ); + } + + $base_country = self::get_base_country(); + $countries = array_diff( $countries, array( $base_country ) ); + + return $countries; + } + + public static function country_supports_eu_vat( $country, $postcode = '' ) { + return self::is_eu_vat_country( $country, $postcode ); + } + + public static function import_oss_tax_rates( $tax_class_slug_names = array() ) { + self::import_tax_rates_internal( true, $tax_class_slug_names ); + } + + public static function import_default_tax_rates( $tax_class_slug_names = array() ) { + self::import_tax_rates_internal( false, $tax_class_slug_names ); + } + + public static function import_tax_rates( $tax_class_slug_names = array() ) { + self::import_tax_rates_internal( self::oss_procedure_is_enabled(), $tax_class_slug_names ); + } + + protected static function parse_tax_class_slug_names( $tax_class_slug_names = array() ) { + return wp_parse_args( + $tax_class_slug_names, + array( + 'reduced' => apply_filters( 'woocommerce_eu_tax_helper_tax_class_reduced_name', __( 'Reduced rate', 'woocommerce' ) ), // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch + 'greater-reduced' => apply_filters( 'woocommerce_eu_tax_helper_tax_class_greater_reduced_name', _x( 'Greater reduced rate', 'tax-helper-tax-class-name', 'woocommerce-germanized' ) ), + 'super-reduced' => apply_filters( 'woocommerce_eu_tax_helper_tax_class_super_reduced_name', _x( 'Super reduced rate', 'tax-helper-tax-class-name', 'woocommerce-germanized' ) ), + ) + ); + } + + protected static function import_tax_rates_internal( $is_oss = true, $tax_class_slug_names = array() ) { + self::clear_cache(); + + $tax_class_slugs = self::get_tax_class_slugs( $tax_class_slug_names ); + $tax_class_slug_names = self::parse_tax_class_slug_names( $tax_class_slug_names ); + $eu_rates = self::get_eu_tax_rates(); + + foreach ( $tax_class_slugs as $tax_class_type => $class ) { + /** + * Maybe create missing tax classes + */ + if ( false === $class ) { + switch ( $tax_class_type ) { + case 'reduced': + /* translators: Do not translate */ + \WC_Tax::create_tax_class( $tax_class_slug_names['reduced'] ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch + break; + case 'greater-reduced': + \WC_Tax::create_tax_class( $tax_class_slug_names['greater-reduced'] ); + break; + case 'super-reduced': + \WC_Tax::create_tax_class( $tax_class_slug_names['super-reduced'] ); + break; + } + } + + $new_rates = array(); + + foreach ( $eu_rates as $country => $rates_data ) { + + /** + * Use base country rates in case OSS is disabled + */ + if ( ! $is_oss ) { + $base_country = self::get_base_country(); + + if ( isset( $eu_rates[ $base_country ] ) ) { + /** + * In case the country includes multiple rules (e.g. postcode exempts) by default + * do only use the last rule (which does not include exempts) to construct non-base country tax rules. + */ + if ( $base_country !== $country ) { + $base_country_base_rate = array_values( array_slice( $eu_rates[ $base_country ], -1 ) )[0]; + + foreach ( $rates_data as $key => $rate_data ) { + $rates_data[ $key ] = array_replace_recursive( $rate_data, $base_country_base_rate ); + + foreach ( $tax_class_slugs as $tmp_class_type => $class_data ) { + /** + * Do not include tax classes which are not supported by the base country. + */ + if ( isset( $rates_data[ $key ][ $tmp_class_type ] ) && ! isset( $base_country_base_rate[ $tmp_class_type ] ) ) { + unset( $rates_data[ $key ][ $tmp_class_type ] ); + } elseif ( isset( $rates_data[ $key ][ $tmp_class_type ] ) ) { + /** + * Replace tax class data with base data to make sure that reduced + * classes have the same dimensions + */ + $rates_data[ $key ][ $tmp_class_type ] = $base_country_base_rate[ $tmp_class_type ]; + + /** + * In case this is an exempt make sure to replace with zero tax rates + */ + if ( isset( $rate_data['is_exempt'] ) && $rate_data['is_exempt'] ) { + if ( is_array( $rates_data[ $key ][ $tmp_class_type ] ) ) { + foreach ( $rates_data[ $key ][ $tmp_class_type ] as $k => $rate ) { + $rates_data[ $key ][ $tmp_class_type ][ $k ] = 0; + } + } else { + $rates_data[ $key ][ $tmp_class_type ] = 0; + } + } + } + } + } + } + } else { + continue; + } + } + + /** + * Each country may contain multiple tax rates + */ + foreach ( $rates_data as $rates ) { + + $rates = wp_parse_args( + $rates, + array( + 'name' => '', + 'postcodes' => array(), + 'reduced' => array(), + ) + ); + + if ( ! empty( $rates['postcode'] ) ) { + foreach ( $rates['postcode'] as $postcode ) { + $tax_rate = self::get_single_tax_rate_data( $tax_class_type, $rates, $country, $postcode ); + + if ( false !== $tax_rate ) { + $new_rates[] = $tax_rate; + } + } + } else { + $tax_rate = self::get_single_tax_rate_data( $tax_class_type, $rates, $country ); + + if ( false !== $tax_rate ) { + $new_rates[] = $tax_rate; + } + } + } + } + + self::import_rates( $new_rates, $class ); + } + } + + private static function get_single_tax_rate_data( $tax_class_type, $rates, $country, $postcode = '' ) { + $rates = wp_parse_args( + $rates, + array( + 'name' => '', + 'reduced' => array(), + ) + ); + + $single_rate = array( + 'name' => $rates['name'], + 'rate' => false, + 'country' => $country, + 'postcode' => $postcode, + ); + + switch ( $tax_class_type ) { + case 'greater-reduced': + if ( count( $rates['reduced'] ) > 1 ) { + $single_rate['rate'] = $rates['reduced'][1]; + } + break; + case 'reduced': + if ( ! empty( $rates['reduced'] ) ) { + $single_rate['rate'] = $rates['reduced'][0]; + } + break; + default: + if ( isset( $rates[ $tax_class_type ] ) ) { + $single_rate['rate'] = $rates[ $tax_class_type ]; + } + break; + } + + if ( false === $single_rate['rate'] ) { + return false; + } + + return $single_rate; + } + + protected static function clear_cache() { + $cache_key = \WC_Cache_Helper::get_cache_prefix( 'taxes' ) . 'eu_tax_helper_tax_class_slugs'; + + wp_cache_delete( $cache_key, 'taxes' ); + } + + public static function get_tax_class_slugs( $tax_class_slug_names = array() ) { + $tax_class_slug_names = self::parse_tax_class_slug_names( $tax_class_slug_names ); + $cache_key = \WC_Cache_Helper::get_cache_prefix( 'taxes' ) . 'eu_tax_helper_tax_class_slugs'; + $slugs = wp_cache_get( $cache_key, 'taxes' ); + + if ( false === $slugs ) { + $reduced_tax_class = false; + $greater_reduced_tax_class = false; + $super_reduced_tax_class = false; + $tax_classes = \WC_Tax::get_tax_class_slugs(); + + /** + * Try to determine the reduced tax rate class + */ + foreach ( $tax_classes as $slug ) { + if ( strstr( $slug, 'virtual' ) ) { + continue; + } + + if ( ! $greater_reduced_tax_class && strstr( $slug, sanitize_title( 'Greater reduced rate' ) ) ) { + $greater_reduced_tax_class = $slug; + } elseif ( ! $greater_reduced_tax_class && strstr( $slug, sanitize_title( $tax_class_slug_names['greater-reduced'] ) ) ) { + $greater_reduced_tax_class = $slug; + } elseif ( ! $super_reduced_tax_class && strstr( $slug, sanitize_title( 'Super reduced rate' ) ) ) { + $super_reduced_tax_class = $slug; + } elseif ( ! $super_reduced_tax_class && strstr( $slug, sanitize_title( $tax_class_slug_names['super-reduced'] ) ) ) { + $super_reduced_tax_class = $slug; + } elseif ( ! $reduced_tax_class && strstr( $slug, sanitize_title( 'Reduced rate' ) ) ) { + $reduced_tax_class = $slug; + } elseif ( ! $reduced_tax_class && strstr( $slug, sanitize_title( $tax_class_slug_names['reduced'] ) ) ) { // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch + $reduced_tax_class = $slug; + } elseif ( ! $reduced_tax_class && strstr( $slug, 'reduced' ) && ! $reduced_tax_class ) { + $reduced_tax_class = $slug; + } + } + + $slugs = array( + 'reduced' => $reduced_tax_class, + 'greater-reduced' => $greater_reduced_tax_class, + 'super-reduced' => $super_reduced_tax_class, + 'standard' => '', + ); + + wp_cache_set( $cache_key, $slugs, 'taxes' ); + } + + return apply_filters( 'woocommerce_eu_tax_helper_tax_rate_class_slugs', $slugs ); + } + + public static function get_tax_type_by_country_rate( $rate_percentage, $country ) { + $country = strtoupper( $country ); + + /** + * Map northern ireland to GB + */ + if ( 'XI' === $country ) { + $country = 'GB'; + } + + $eu_rates = self::get_eu_tax_rates(); + $tax_type = 'standard'; + + if ( array_key_exists( $country, $eu_rates ) ) { + $rates = $eu_rates[ $country ]; + + foreach ( $rates as $rate ) { + foreach ( $rate as $tax_rate_type => $tax_rate_percent ) { + if ( ( is_array( $tax_rate_percent ) && in_array( $rate_percentage, $tax_rate_percent, true ) ) || (float) $tax_rate_percent === (float) $rate_percentage ) { + $tax_type = $tax_rate_type; + break; + } + } + } + } + + return apply_filters( 'woocommerce_eu_tax_helper_country_rate_tax_type', $tax_type, $country, $rate_percentage ); + } + + public static function get_eu_tax_rates() { + /** + * @see https://europa.eu/youreurope/business/taxation/vat/vat-rules-rates/index_en.htm + * + * Include Great Britain to allow including Norther Ireland + */ + $rates = array( + 'AT' => array( + array( + 'standard' => 20, + 'reduced' => array( 10, 13 ), + ), + ), + 'BE' => array( + array( + 'standard' => 21, + 'reduced' => array( 6, 12 ), + ), + ), + 'BG' => array( + array( + 'standard' => 20, + 'reduced' => array( 9 ), + ), + ), + 'CY' => array( + array( + 'standard' => 19, + 'reduced' => array( 5, 9 ), + ), + ), + 'CZ' => array( + array( + 'standard' => 21, + 'reduced' => array( 10, 15 ), + ), + ), + 'DE' => array( + array( + 'standard' => 19, + 'reduced' => array( 7 ), + ), + ), + 'DK' => array( + array( + 'standard' => 25, + 'reduced' => array(), + ), + ), + 'EE' => array( + array( + 'standard' => 20, + 'reduced' => array( 9 ), + ), + ), + 'GR' => array( + array( + 'standard' => 24, + 'reduced' => array( 6, 13 ), + ), + ), + 'ES' => array( + array( + 'standard' => 21, + 'reduced' => array( 10 ), + 'super-reduced' => 4, + ), + ), + 'FI' => array( + array( + 'standard' => 24, + 'reduced' => array( 10, 14 ), + ), + ), + 'FR' => array( + array( + 'standard' => 20, + 'reduced' => array( 5.5, 10 ), + 'super-reduced' => 2.1, + ), + ), + 'HR' => array( + array( + 'standard' => 25, + 'reduced' => array( 5, 13 ), + ), + ), + 'HU' => array( + array( + 'standard' => 27, + 'reduced' => array( 5, 18 ), + ), + ), + 'IE' => array( + array( + 'standard' => 23, + 'reduced' => array( 9, 13.5 ), + 'super-reduced' => 4.8, + ), + ), + 'IT' => array( + array( + 'standard' => 22, + 'reduced' => array( 5, 10 ), + 'super-reduced' => 4, + ), + ), + 'LT' => array( + array( + 'standard' => 21, + 'reduced' => array( 5, 9 ), + ), + ), + 'LU' => array( + array( + 'standard' => 17, + 'reduced' => array( 8 ), + 'super-reduced' => 3, + ), + ), + 'LV' => array( + array( + 'standard' => 21, + 'reduced' => array( 12, 5 ), + ), + ), + 'MC' => array( + array( + 'standard' => 20, + 'reduced' => array( 5.5, 10 ), + 'super-reduced' => 2.1, + ), + ), + 'MT' => array( + array( + 'standard' => 18, + 'reduced' => array( 5, 7 ), + ), + ), + 'NL' => array( + array( + 'standard' => 21, + 'reduced' => array( 9 ), + ), + ), + 'PL' => array( + array( + 'standard' => 23, + 'reduced' => array( 5, 8 ), + ), + ), + 'PT' => array( + array( + // Madeira + 'postcode' => array( '90*', '91*', '92*', '93*', '94*' ), + 'standard' => 22, + 'reduced' => array( 5, 12 ), + 'name' => _x( 'Madeira', 'tax-helper', 'woocommerce-germanized' ), + ), + array( + // Acores + 'postcode' => array( '95*', '96*', '97*', '98*', '99*' ), + 'standard' => 18, + 'reduced' => array( 4, 9 ), + 'name' => _x( 'Acores', 'tax-helper', 'woocommerce-germanized' ), + ), + array( + 'standard' => 23, + 'reduced' => array( 6, 13 ), + ), + ), + 'RO' => array( + array( + 'standard' => 19, + 'reduced' => array( 5, 9 ), + ), + ), + 'SE' => array( + array( + 'standard' => 25, + 'reduced' => array( 6, 12 ), + ), + ), + 'SI' => array( + array( + 'standard' => 22, + 'reduced' => array( 9.5 ), + ), + ), + 'SK' => array( + array( + 'standard' => 20, + 'reduced' => array( 10 ), + ), + ), + 'GB' => array( + array( + 'standard' => 20, + 'reduced' => array( 5 ), + 'postcode' => array( 'BT*' ), + 'name' => _x( 'Northern Ireland', 'tax-helper', 'woocommerce-germanized' ), + ), + ), + ); + + foreach ( self::get_vat_postcode_exemptions_by_country() as $country => $exempt_postcodes ) { + if ( array_key_exists( $country, $rates ) ) { + $default_rate = array_values( $rates[ $country ] )[0]; + + $postcode_exempt = array( + 'postcode' => $exempt_postcodes, + 'standard' => 0, + 'reduced' => count( $default_rate['reduced'] ) > 1 ? array( 0, 0 ) : array( 0 ), + 'name' => _x( 'Exempt', 'tax-helper-rate-import', 'woocommerce-germanized' ), + 'is_exempt' => true, + ); + + if ( array_key_exists( 'super-reduced', $default_rate ) ) { + $postcode_exempt['super-reduced'] = 0; + } + + // Prepend before other tax rates + $rates[ $country ] = array_merge( array( $postcode_exempt ), $rates[ $country ] ); + } + } + + return $rates; + } + + /** + * @param \stdClass $rate + * + * @return bool + */ + public static function tax_rate_is_northern_ireland( $rate ) { + if ( 'GB' === $rate->tax_rate_country && isset( $rate->postcode ) && ! empty( $rate->postcode ) ) { + foreach ( $rate->postcode as $postcode ) { + if ( self::is_northern_ireland( $rate->tax_rate_country, $postcode ) ) { + return true; + } + } + } + + return false; + } + + public static function import_rates( $rates, $tax_class = '' ) { + global $wpdb; + + $eu_countries = self::get_eu_vat_countries(); + + /** + * Delete EU tax rates and make sure tax rate locations are deleted too + */ + foreach ( \WC_Tax::get_rates_for_tax_class( $tax_class ) as $rate_id => $rate ) { + if ( in_array( $rate->tax_rate_country, $eu_countries, true ) || self::tax_rate_is_northern_ireland( $rate ) || ( 'GB' === $rate->tax_rate_country && 'GB' !== self::get_base_country() ) ) { + \WC_Tax::_delete_tax_rate( $rate_id ); + } + } + + $count = 0; + + foreach ( $rates as $rate ) { + $rate = wp_parse_args( + $rate, + array( + 'rate' => 0, + 'country' => '', + 'postcode' => '', + 'name' => '', + ) + ); + + $iso = wc_strtoupper( $rate['country'] ); + $vat_desc = $iso; + + if ( ! empty( $rate['name'] ) ) { + $vat_desc = $vat_desc . ' ' . $rate['name']; + } + + $vat_rate = wc_format_decimal( $rate['rate'], false, true ); + + $tax_rate_name = apply_filters( 'woocommerce_eu_tax_helper_import_tax_rate_name', sprintf( _x( 'VAT %1$s %% %2$s', 'tax-helper-rate-import', 'woocommerce-germanized' ), $vat_rate, $vat_desc ), $rate['rate'], $iso, $tax_class, $rate ); + + $_tax_rate = array( + 'tax_rate_country' => $iso, + 'tax_rate_state' => '', + 'tax_rate' => (string) number_format( (float) wc_clean( $rate['rate'] ), 4, '.', '' ), + 'tax_rate_name' => $tax_rate_name, + 'tax_rate_compound' => 0, + 'tax_rate_priority' => 1, + 'tax_rate_order' => $count++, + 'tax_rate_shipping' => ( strstr( $tax_class, 'virtual' ) ? 0 : 1 ), + 'tax_rate_class' => $tax_class, + ); + + $new_tax_rate_id = \WC_Tax::_insert_tax_rate( $_tax_rate ); + + if ( ! empty( $rate['postcode'] ) ) { + \WC_Tax::_update_tax_rate_postcodes( $new_tax_rate_id, $rate['postcode'] ); + } + } + } + + /** + * @param $rate_id + * @param \WC_Order $order + */ + public static function get_tax_rate_percent( $rate_id, $order ) { + $taxes = $order->get_taxes(); + $percentage = null; + + foreach ( $taxes as $tax ) { + if ( (int) $tax->get_rate_id() === (int) $rate_id ) { + if ( is_callable( array( $tax, 'get_rate_percent' ) ) ) { + $percentage = $tax->get_rate_percent(); + } + } + } + + /** + * WC_Order_Item_Tax::get_rate_percent returns null by default. + * Fallback to global tax rates (DB) in case the percentage is not available within order data. + */ + if ( is_null( $percentage ) || '' === $percentage ) { + $rate_percentage = self::get_tax_rate_percentage( $rate_id ); + + if ( false !== $rate_percentage ) { + $percentage = $rate_percentage; + } + } + + if ( ! is_numeric( $percentage ) ) { + $percentage = 0; + } + + return $percentage; + } + + public static function get_tax_rate_percentage( $rate_id ) { + $percentage = false; + + if ( is_callable( array( 'WC_Tax', 'get_rate_percent_value' ) ) ) { + $percentage = \WC_Tax::get_rate_percent_value( $rate_id ); + } elseif ( is_callable( array( 'WC_Tax', 'get_rate_percent' ) ) ) { + $percentage = filter_var( \WC_Tax::get_rate_percent( $rate_id ), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION ); + } + + return $percentage; + } +} diff --git a/packages/one-stop-shop-woocommerce/license.txt b/packages/one-stop-shop-woocommerce/license.txt new file mode 100644 index 000000000..76adc409b --- /dev/null +++ b/packages/one-stop-shop-woocommerce/license.txt @@ -0,0 +1,699 @@ +One Stop Shop WooCommerce + +Copyright 2011 by the contributors + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +This program incorporates work covered by the following copyright and +permission notices: + + WooCommerce + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright © 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright © + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright © + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file diff --git a/packages/one-stop-shop-woocommerce/one-stop-shop-woocommerce.php b/packages/one-stop-shop-woocommerce/one-stop-shop-woocommerce.php new file mode 100644 index 000000000..0fcb99c23 --- /dev/null +++ b/packages/one-stop-shop-woocommerce/one-stop-shop-woocommerce.php @@ -0,0 +1,77 @@ + +
+

+ composer install', + '' . esc_html( str_replace( ABSPATH, '', __DIR__ ) ) . '' + ); + ?> +

+
+ get_name() === $wc_admin_note_name ) { + /** + * Update notice hide in case note has been actioned (e.g. button click by user) + */ + if ( Note::E_WC_ADMIN_NOTE_ACTIONED === $note->get_status() ) { + update_option( 'oss_hide_notice_' . sanitize_key( $oss_note::get_id() ), 'yes' ); + } + + break; + } + } + } + } catch ( \Exception $e ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch + } + } + + public static function register_tax_rate_refresh_tool( $tools ) { + $tools['refresh_oss_tax_rates'] = array( + 'name' => _x( 'Refresh VAT rates (OSS)', 'oss', 'woocommerce-germanized' ), + 'button' => _x( 'Refresh VAT rates (OSS)', 'oss', 'woocommerce-germanized' ), + 'callback' => array( __CLASS__, 'refresh_vat_rates' ), + 'desc' => sprintf( + '%1$s %2$s', + _x( 'Note:', 'oss', 'woocommerce-germanized' ), + sprintf( _x( 'This option will delete all of your current EU VAT rates and re-import them based on your current OSS status.', 'oss', 'woocommerce-germanized' ), esc_url( Settings::get_settings_url() ) ) + ), + ); + + return $tools; + } + + public static function refresh_vat_rates() { + if ( Helper::oss_procedure_is_enabled() ) { + Helper::import_oss_tax_rates(); + } else { + Helper::import_default_tax_rates(); + } + } + + public static function html_field( $value ) { + ?> + + + + + + + id : ''; + $supports_notes = self::supports_wc_admin(); + + if ( ! $supports_notes || in_array( $screen_id, array( 'dashboard', 'plugins' ), true ) ) { + foreach ( self::get_notes() as $note ) { + if ( $note::is_enabled() ) { + $note::render(); + } + } + } + } + + /** + * @return AdminNote[] + */ + public static function get_notes() { + $notes = array( 'Vendidero\OneStopShop\DeliveryThresholdWarning' ); + + if ( ! Package::enable_auto_observer() ) { + $notes = array(); + } + + return $notes; + } + + public static function supports_wc_admin() { + $supports_notes = class_exists( 'Automattic\WooCommerce\Admin\Notes\Note' ); + + try { + $data_store = \WC_Data_Store::load( 'admin-note' ); + } catch ( \Exception $e ) { + $supports_notes = false; + } + + return $supports_notes; + } + + protected static function get_wc_admin_note_name( $oss_note_id ) { + return 'oss_' . $oss_note_id; + } + + protected static function get_wc_admin_note( $oss_note_id ) { + $note_name = self::get_wc_admin_note_name( $oss_note_id ); + $data_store = \WC_Data_Store::load( 'admin-note' ); + $note_ids = $data_store->get_notes_with_name( $note_name ); + + if ( ! empty( $note_ids ) && ( $note = Notes::get_note( $note_ids[0] ) ) ) { + return $note; + } + + return false; + } + + public static function queue_wc_admin_notes() { + if ( self::supports_wc_admin() ) { + foreach ( self::get_notes() as $oss_note ) { + $note = self::get_wc_admin_note( $oss_note::get_id() ); + + if ( ! $note && $oss_note::is_enabled() ) { + $note = new Note(); + $note->set_title( $oss_note::get_title() ); + $note->set_content( $oss_note::get_content() ); + $note->set_content_data( (object) array() ); + $note->set_type( 'update' ); + $note->set_name( self::get_wc_admin_note_name( $oss_note::get_id() ) ); + $note->set_source( 'oss-woocommerce' ); + $note->set_status( Note::E_WC_ADMIN_NOTE_UNACTIONED ); + + foreach ( $oss_note::get_actions() as $action ) { + $note->add_action( + 'oss_' . sanitize_key( $action['title'] ), + $action['title'], + $action['url'], + Note::E_WC_ADMIN_NOTE_ACTIONED, + $action['is_primary'] ? true : false + ); + } + + $note->save(); + } elseif ( $oss_note::is_enabled() && $note ) { + $note->set_status( Note::E_WC_ADMIN_NOTE_UNACTIONED ); + $note->save(); + } + } + } + } + + public static function get_threshold_notice_content() { + return sprintf( _x( 'Seems like you have reached (or are close to reaching) the delivery threshold for the current year. Please make sure to check the report details and take action in case necessary.', 'oss', 'woocommerce-germanized' ), esc_url( Package::get_observer_report()->get_url() ) ); + } + + public static function get_threshold_notice_title() { + return _x( 'Delivery threshold reached (OSS)', 'oss', 'woocommerce-germanized' ); + } + + public static function init_observer() { + if ( ! current_user_can( 'manage_woocommerce' ) || ! wp_verify_nonce( isset( $_GET['_wpnonce'] ) ? wp_unslash( $_GET['_wpnonce'] ) : '', 'oss_init_observer' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + wp_die(); + } + + if ( ! Queue::get_running_observer() ) { + Package::update_observer_report(); + } + + wp_safe_redirect( wp_get_referer() ); + exit(); + } + + public static function switch_procedure() { + if ( ! current_user_can( 'manage_woocommerce' ) || ! wp_verify_nonce( isset( $_GET['_wpnonce'] ) ? wp_unslash( $_GET['_wpnonce'] ) : '', 'oss_switch_procedure' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + wp_die(); + } + + if ( Helper::oss_procedure_is_enabled() ) { + update_option( 'oss_use_oss_procedure', 'no' ); + + Helper::import_default_tax_rates(); + + do_action( 'woocommerce_oss_disabled_oss_procedure' ); + } else { + update_option( 'woocommerce_tax_based_on', 'shipping' ); + update_option( 'oss_use_oss_procedure', 'yes' ); + + Helper::import_oss_tax_rates(); + + do_action( 'woocommerce_oss_enabled_oss_procedure' ); + } + + do_action( 'woocommerce_oss_switched_oss_procedure_status' ); + + wp_safe_redirect( wp_get_referer() ); + exit(); + } + + public static function hide_notice() { + if ( ! current_user_can( 'manage_woocommerce' ) || ! wp_verify_nonce( isset( $_GET['_wpnonce'] ) ? wp_unslash( $_GET['_wpnonce'] ) : '', 'oss_hide_notice' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + wp_die(); + } + + $notice_id = isset( $_GET['notice'] ) ? wc_clean( wp_unslash( $_GET['notice'] ) ) : ''; + + foreach ( self::get_notes() as $oss_note ) { + if ( $oss_note::get_id() === $notice_id ) { + update_option( 'oss_hide_notice_' . sanitize_key( $oss_note::get_id() ), 'yes' ); + + if ( self::supports_wc_admin() ) { + self::delete_wc_admin_note( $oss_note ); + } + + break; + } + } + + wp_safe_redirect( wp_get_referer() ); + exit(); + } + + /** + * @param AdminNote $oss_note + */ + public static function delete_wc_admin_note( $oss_note ) { + if ( ! self::supports_wc_admin() ) { + return false; + } + + try { + if ( $note = self::get_wc_admin_note( $oss_note::get_id() ) ) { + $note->delete( true ); + return true; + } + + return false; + } catch ( \Exception $e ) { + return false; + } + } + + public static function delete_report() { + if ( ! current_user_can( 'manage_woocommerce' ) || ! wp_verify_nonce( isset( $_GET['_wpnonce'] ) ? wp_unslash( $_GET['_wpnonce'] ) : '', 'oss_delete_report' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + wp_die(); + } + + $report_id = isset( $_GET['report_id'] ) ? wc_clean( wp_unslash( $_GET['report_id'] ) ) : ''; + + if ( ! empty( $report_id ) && ( $report = Package::get_report( $report_id ) ) ) { + $report->delete(); + + $referer = self::get_clean_referer(); + + /** + * Do not redirect deleted, refreshed reports back to report details page + */ + if ( strstr( $referer, '&report=' ) ) { + $referer = admin_url( 'admin.php?page=oss-reports' ); + } + + wp_safe_redirect( esc_url_raw( add_query_arg( array( 'report_deleted' => $report_id ), $referer ) ) ); + exit(); + } + + wp_safe_redirect( esc_url_raw( wp_get_referer() ) ); + exit(); + } + + protected static function get_clean_referer() { + $referer = wp_get_referer(); + + return remove_query_arg( array( 'report_created', 'report_deleted', 'report_restarted', 'report_cancelled' ), $referer ); + } + + public static function export_report() { + if ( ! current_user_can( 'manage_woocommerce' ) || ! wp_verify_nonce( isset( $_GET['_wpnonce'] ) ? wp_unslash( $_GET['_wpnonce'] ) : '', 'oss_export_report' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + wp_die(); + } + + $report_id = isset( $_GET['report_id'] ) ? wc_clean( wp_unslash( $_GET['report_id'] ) ) : ''; + $decimals = isset( $_GET['decimals'] ) ? absint( wp_unslash( $_GET['decimals'] ) ) : wc_get_price_decimals(); + $export_type = isset( $_GET['export_type'] ) ? wc_clean( wp_unslash( $_GET['export_type'] ) ) : ''; + + if ( ! empty( $report_id ) && ( $report = Package::get_report( $report_id ) ) ) { + $exporter_class = '\Vendidero\OneStopShop\CSVExporter'; + $base_country = Helper::get_base_country(); + + if ( 'bop' === $export_type ) { + $exporter_class = '\Vendidero\OneStopShop\CSVExporterBOP'; + } + + $exporter_class = apply_filters( 'oss_csv_exporter_classname', $exporter_class, $base_country ); + + if ( ! class_exists( $exporter_class ) ) { + $exporter_class = '\Vendidero\OneStopShop\CSVExporter'; + } + + $csv = new $exporter_class( $report_id, $decimals ); + $csv->export(); + } else { + wp_safe_redirect( wp_get_referer() ); + exit(); + } + } + + public static function refresh_report() { + if ( ! current_user_can( 'manage_woocommerce' ) || ! wp_verify_nonce( isset( $_GET['_wpnonce'] ) ? wp_unslash( $_GET['_wpnonce'] ) : '', 'oss_refresh_report' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + wp_die(); + } + + $report_id = isset( $_GET['report_id'] ) ? wc_clean( wp_unslash( $_GET['report_id'] ) ) : ''; + + if ( ! empty( $report_id ) && ( $report = Package::get_report( $report_id ) ) ) { + Queue::start( $report->get_type(), $report->get_date_start(), $report->get_date_end() ); + + wp_safe_redirect( esc_url_raw( add_query_arg( array( 'report_restarted' => $report_id ), self::get_clean_referer() ) ) ); + exit(); + } + + wp_safe_redirect( esc_url_raw( wp_get_referer() ) ); + exit(); + } + + public static function cancel_report() { + if ( ! current_user_can( 'manage_woocommerce' ) || ! wp_verify_nonce( isset( $_GET['_wpnonce'] ) ? wp_unslash( $_GET['_wpnonce'] ) : '', 'oss_cancel_report' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + wp_die(); + } + + $report_id = isset( $_GET['report_id'] ) ? wc_clean( wp_unslash( $_GET['report_id'] ) ) : ''; + + if ( ! empty( $report_id ) && Queue::is_running( $report_id ) ) { + Queue::cancel( $report_id ); + + $referer = self::get_clean_referer(); + + /** + * Do not redirect deleted, refreshed reports back to report details page + */ + if ( strstr( $referer, '&report=' ) ) { + $referer = admin_url( 'admin.php?page=oss-reports' ); + } + + wp_safe_redirect( esc_url_raw( add_query_arg( array( 'report_cancelled' => $report_id ), $referer ) ) ); + exit(); + } + + wp_safe_redirect( esc_url_raw( wp_get_referer() ) ); + exit(); + } + + public static function create_report() { + if ( ! current_user_can( 'manage_woocommerce' ) || ! wp_verify_nonce( isset( $_POST['_wpnonce'] ) ? wp_unslash( $_POST['_wpnonce'] ) : '', 'oss_create_report' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + wp_die(); + } + + $report_type = ! empty( $_POST['report_type'] ) ? wc_clean( wp_unslash( $_POST['report_type'] ) ) : 'yearly'; + $report_type = array_key_exists( $report_type, Package::get_available_report_types() ) ? $report_type : 'yearly'; + $start_date = null; + $end_date = null; + + if ( 'quarterly' === $report_type ) { + $start_date = ! empty( $_POST['report_quarter'] ) ? wc_clean( wp_unslash( $_POST['report_quarter'] ) ) : null; + } elseif ( 'yearly' === $report_type ) { + $start_date = ! empty( $_POST['report_year'] ) ? wc_clean( wp_unslash( $_POST['report_year'] ) ) : null; + } elseif ( 'monthly' === $report_type ) { + $start_date = ! empty( $_POST['report_month'] ) ? wc_clean( wp_unslash( $_POST['report_month'] ) ) : null; + } elseif ( 'custom' === $report_type ) { + $start_date = ! empty( $_POST['date_start'] ) ? wc_clean( wp_unslash( $_POST['date_start'] ) ) : null; + $end_date = ! empty( $_POST['date_end'] ) ? wc_clean( wp_unslash( $_POST['date_end'] ) ) : null; + } + + if ( ! is_null( $start_date ) ) { + $start_date = Package::string_to_datetime( $start_date ); + } + + if ( ! is_null( $end_date ) ) { + $end_date = Package::string_to_datetime( $end_date ); + } + + $generator_id = Queue::start( $report_type, $start_date, $end_date ); + + wp_safe_redirect( admin_url( 'admin.php?page=oss-reports&report_created=' . $generator_id ) ); + exit(); + } + + public static function add_menu() { + add_submenu_page( 'woocommerce', _x( 'OSS', 'oss', 'woocommerce-germanized' ), _x( 'One Stop Shop', 'oss', 'woocommerce-germanized' ), 'manage_woocommerce', 'oss-reports', array( __CLASS__, 'render_report_page' ) ); + } + + protected static function render_create_report() { + $years = array(); + $years[] = date( 'Y' ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date + $years[] = date( 'Y', strtotime( '-1 year' ) ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date + + $quarters_selectable = array(); + $years_selectable = array(); + $months_selectable = array(); + + foreach ( $years as $year ) { + $start_day = date( 'Y-m-d', strtotime( $year . '-01-01' ) ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date + $years_selectable[ $start_day ] = $year; + + for ( $i = 4; $i >= 1; $i-- ) { + $start_month = ( $i - 1 ) * 3 + 1; + $start_day = date( 'Y-m-d', strtotime( $year . '-' . $start_month . '-01' ) ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date + + if ( date( 'Y-m-d' ) >= $start_day ) { // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date + $quarters_selectable[ $start_day ] = sprintf( _x( 'Q%1$s/%2$s', 'oss', 'woocommerce-germanized' ), $i, $year ); + } + } + + for ( $i = 12; $i >= 1; $i-- ) { + $start_day = date( 'Y-m-d', strtotime( $year . '-' . $i . '-01' ) ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date + $month = date( 'm', strtotime( $year . '-' . $i . '-01' ) ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date + + if ( date( 'Y-m-d' ) >= $start_day ) { // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date + $months_selectable[ $start_day ] = sprintf( _x( '%1$s/%2$s', 'oss', 'woocommerce-germanized' ), $month, $year ); + } + } + } + ?> +
+
+
+

+
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+
+
+ +
+ + +
+
+ +
+

+ + +
+ + output_notices(); + $_SERVER['REQUEST_URI'] = remove_query_arg( array( 'updated', 'changed', 'deleted', 'trashed', 'untrashed' ), ( isset( $_SERVER['REQUEST_URI'] ) ? esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : admin_url( 'admin.php?page=oss-reports' ) ) ); + ?> + + views(); ?> + +
+ + + display(); ?> +
+ +
+
+
+ $action ) { + if ( isset( $action['url'] ) ) { + $target = isset( $action['target'] ) ? $action['target'] : '_self'; + + printf( '%5$s', esc_attr( $action_name ), esc_url( $action['url'] ), ( ( isset( $action['title'] ) ) ? esc_attr( $action['title'] ) : esc_attr( $action_name ) ), esc_attr( $target ), ( isset( $action['title'] ) ? esc_html( $action['title'] ) : esc_html( $action_name ) ) ); + } + } + } + + /** + * @param Report $report + * + * @return array[] + */ + public static function get_report_actions( $report ) { + $actions = array( + 'view' => array( + 'url' => $report->get_url(), + 'title' => _x( 'View', 'oss', 'woocommerce-germanized' ), + ), + 'export' => array( + 'url' => $report->get_export_link(), + 'title' => _x( 'Export', 'oss', 'woocommerce-germanized' ), + ), + 'export_bop' => array( + 'url' => $report->get_export_link( 'bop' ), + 'title' => _x( 'Export BOP', 'oss', 'woocommerce-germanized' ), + ), + 'refresh' => array( + 'url' => $report->get_refresh_link(), + 'title' => _x( 'Refresh', 'oss', 'woocommerce-germanized' ), + ), + 'delete' => array( + 'url' => $report->get_delete_link(), + 'title' => _x( 'Delete', 'oss', 'woocommerce-germanized' ), + ), + ); + + if ( 'completed' !== $report->get_status() ) { + $actions['cancel'] = $actions['delete']; + $actions['cancel']['title'] = _x( 'Cancel', 'oss', 'woocommerce-germanized' ); + + unset( $actions['view'] ); + unset( $actions['refresh'] ); + unset( $actions['delete'] ); + unset( $actions['export'] ); + unset( $actions['export_bop'] ); + } + + if ( 'DE' !== Helper::get_base_country() && isset( $actions['export_bop'] ) ) { + unset( $actions['export_bop'] ); + } + + if ( 'observer' === $report->get_type() ) { + unset( $actions['refresh'] ); + unset( $actions['cancel'] ); + } + + return $actions; + } + + public static function render_report_details() { + global $wp_list_table; + + $report_id = isset( $_GET['report'] ) ? wc_clean( wp_unslash( $_GET['report'] ) ) : false; // phpcs:ignore WordPress.Security.NonceVerification.Recommended + + if ( ! $report_id ) { + return; + } + + if ( ! $report = Package::get_report( $report_id ) ) { + return; + } + + $actions = self::get_report_actions( $report ); + unset( $actions['view'] ); + + $columns = array( + 'country' => _x( 'Country', 'oss', 'woocommerce-germanized' ), + 'tax_rate' => _x( 'Tax Rate', 'oss', 'woocommerce-germanized' ), + 'net_total' => _x( 'Net Total', 'oss', 'woocommerce-germanized' ), + 'tax_total' => _x( 'Tax Total', 'oss', 'woocommerce-germanized' ), + ); + + $countries = $report->get_countries(); + ?> +
+

get_title() ); ?>

+ + $action ) : ?> + + + + get_status() ) : ?> +

get_date_start()->date_i18n( wc_date_format() ) ); ?> – get_date_end()->date_i18n( wc_date_format() ) ); ?>: get_net_total() ); ?> (get_tax_total() ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>)

+
+ + + + + $column ) : ?> + + + + + + get_tax_rates_by_country( $country ) as $tax_rate ) : + ?> + + + + + + + + + +
get_country_net_total( $country, $tax_rate ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>get_country_tax_total( $country, $tax_rate ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
+ + +

Find pending actions', 'oss', 'woocommerce-germanized' ), esc_html( $details['order_count'] ), ( $details['next_date'] ? esc_html( $details['next_date']->date_i18n( wc_date_format() . ' @ ' . wc_time_format() ) ) : esc_html_x( 'Not yet known', 'oss', 'woocommerce-germanized' ) ), esc_url( $details['link'] ) ); ?>

+ +
+ current_action(); + + if ( $doaction ) { + /** + * This nonce is dynamically constructed by WP_List_Table and uses + * the normalized plural argument. + */ + check_admin_referer( 'bulk-' . sanitize_key( _x( 'Reports', 'oss', 'woocommerce-germanized' ) ) ); + + $pagenum = $wp_list_table->get_pagenum(); + $parent_file = $wp_list_table->get_main_page(); + $sendback = remove_query_arg( array( 'deleted', 'ids', 'changed', 'bulk_action' ), wp_get_referer() ); + + if ( ! $sendback ) { + $sendback = admin_url( $parent_file ); + } + + $sendback = add_query_arg( 'paged', $pagenum, $sendback ); + $report_ids = array(); + + if ( isset( $_REQUEST['ids'] ) ) { + $report_ids = explode( ',', wc_clean( wp_unslash( $_REQUEST['ids'] ) ) ); + } elseif ( ! empty( $_REQUEST['report'] ) ) { + $report_ids = wc_clean( wp_unslash( $_REQUEST['report'] ) ); + } + + if ( ! empty( $report_ids ) ) { + $sendback = $wp_list_table->handle_bulk_actions( $doaction, $report_ids, $sendback ); + } + + $sendback = remove_query_arg( array( 'action', 'action2', '_status', 'bulk_edit', 'report', 'report_created' ), $sendback ); + + wp_safe_redirect( esc_url_raw( $sendback ) ); + exit(); + } elseif ( ! empty( $_REQUEST['_wp_http_referer'] ) ) { + wp_safe_redirect( esc_url_raw( remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) ) ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated + exit; + } + + $wp_list_table->set_bulk_notice(); + $wp_list_table->prepare_items(); + + add_screen_option( 'per_page' ); + } + + public static function register_settings( $settings ) { + if ( ! Package::is_integration() ) { + $settings[] = new SettingsPage(); + } + + return $settings; + } + + public static function get_screen_ids() { + $screen_ids = array( 'woocommerce_page_wc-settings', 'woocommerce_page_oss-reports', 'product' ); + + return $screen_ids; + } + + public static function admin_styles() { + $screen = get_current_screen(); + $screen_id = $screen ? $screen->id : ''; + $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; + + wp_register_style( 'oss_woo', Package::get_url() . '/assets/css/admin' . $suffix . '.css', array(), Package::get_version() ); + + // Admin styles for WC pages only. + if ( in_array( $screen_id, self::get_screen_ids(), true ) ) { + wp_enqueue_style( 'oss_woo' ); + } + } + + public static function admin_scripts() { + global $post; + + $screen = get_current_screen(); + $screen_id = $screen ? $screen->id : ''; + $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; + $deps = array( 'jquery', 'woocommerce_admin' ); + + if ( in_array( $screen_id, array( 'woocommerce_page_oss-reports' ), true ) ) { + $deps[] = 'jquery-ui-datepicker'; + } + + wp_register_script( 'oss-admin', Package::get_assets_url() . '/js/admin' . $suffix . '.js', $deps, Package::get_version() ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.NotInFooter + + if ( in_array( $screen_id, self::get_screen_ids(), true ) ) { + wp_enqueue_script( 'oss-admin' ); + + wp_localize_script( + 'oss-admin', + 'oss_admin_params', + array( + 'ajax_url' => admin_url( 'admin-ajax.php' ), + ) + ); + } + } +} diff --git a/packages/one-stop-shop-woocommerce/src/AdminNote.php b/packages/one-stop-shop-woocommerce/src/AdminNote.php new file mode 100644 index 000000000..c5c6eef9d --- /dev/null +++ b/packages/one-stop-shop-woocommerce/src/AdminNote.php @@ -0,0 +1,92 @@ + 'oss_hide_notice', + 'notice' => static::get_id(), + '_wpnonce' => wp_create_nonce( 'oss_hide_notice' ), + ), + admin_url( 'admin-post.php' ) + ); + } + + public static function has_actions() { + $actions = static::get_actions(); + + return empty( $actions ) ? false : true; + } + + public static function get_actions() { + return array( + array( + 'target' => '', + 'title' => _x( 'Dismiss', 'oss', 'woocommerce-germanized' ), + 'url' => static::get_dismiss_url(), + 'is_primary' => false, + ), + ); + } + + public static function is_enabled() { + $enabled = true; + + if ( 'yes' === get_option( 'oss_hide_notice_' . sanitize_key( static::get_id() ) ) ) { + $enabled = false; + } + + return $enabled; + } + + public static function render() { + ?> +
+ + +

+ + + +

+ '', + 'url' => '', + 'is_primary' => true, + 'target' => '_blank', + ) + ); + ?> + + +

+ +
+ type = $type; + $default_end = new \WC_DateTime(); + $default_start = new \WC_DateTime( 'now' ); + $default_start->modify( '-1 year' ); + + $args = wp_parse_args( + $args, + array( + 'start' => $default_start->format( 'Y-m-d' ), + 'end' => $default_end->format( 'Y-m-d' ), + 'limit' => Queue::get_batch_size(), + 'status' => Queue::get_order_statuses(), + 'offset' => 0, + 'order_types' => array( 'shop_order' ), + 'orders_processed' => 0, + 'date_field' => Queue::use_date_paid() ? 'date_paid' : 'date_created', + ) + ); + + /** + * Observers do not treat refunds separately + */ + if ( 'observer' === $type ) { + $args['order_types'] = array( 'shop_order' ); + } + + foreach ( array( 'start', 'end' ) as $date_field ) { + if ( is_a( $args[ $date_field ], 'WC_DateTime' ) ) { + $args[ $date_field ] = $args[ $date_field ]->format( 'Y-m-d' ); + } elseif ( is_numeric( $args[ $date_field ] ) ) { + $date = new \WC_DateTime( '@' . $args[ $date_field ] ); + $args[ $date_field ] = $date->format( 'Y-m-d' ); + } + } + + $this->args = $args; + } + + public function get_type() { + return $this->type; + } + + public function get_args() { + return $this->args; + } + + public function get_id() { + return sanitize_key( 'oss_' . $this->type . '_report_' . $this->args['start'] . '_' . $this->args['end'] ); + } + + public function delete() { + $report = new Report( $this->get_id() ); + $report->delete(); + + delete_option( $this->get_id() . '_tmp_result' ); + } + + public function start() { + $report = new Report( $this->get_id() ); + $report->reset(); + $report->save(); + + return $report; + } + + /** + * @param \WC_Order $order + * + * @return mixed + */ + protected function get_order_taxable_country( $order ) { + if ( ! is_callable( array( $order, 'get_shipping_country' ) ) ) { + return Helper::get_base_country(); + } + + $taxable_country_type = ! empty( $order->get_shipping_country() ) ? 'shipping' : 'billing'; + $taxable_country = 'shipping' === $taxable_country_type ? $order->get_shipping_country() : $order->get_billing_country(); + + return $taxable_country; + } + + /** + * @param \WC_Order $order + * + * @return mixed + */ + protected function get_order_taxable_postcode( $order ) { + $taxable_type = ! empty( $order->get_shipping_postcode() ) ? 'shipping' : 'billing'; + $taxable_postcode = 'shipping' === $taxable_type ? $order->get_shipping_postcode() : $order->get_billing_postcode(); + + return $taxable_postcode; + } + + /** + * @param \WC_Order $order + * + * @return bool + */ + protected function include_order( $order ) { + $taxable_country = $this->get_order_taxable_country( $order ); + $taxable_postcode = $this->get_order_taxable_postcode( $order ); + $included = true; + + if ( ! Helper::is_eu_vat_country( $taxable_country, $taxable_postcode ) ) { + $included = false; + } + + if ( floatval( $order->get_total_tax() ) === 0.0 ) { + $included = false; + } + + return apply_filters( 'oss_woocommerce_report_include_order', $included, $order ); + } + + protected function get_taxable_country_iso( $country ) { + if ( 'GB' === $country ) { + $country = 'XI'; + } + + return $country; + } + + /** + * @param \WC_Order|\WC_Order_Refund $order + */ + protected function get_order_number( $order ) { + if ( is_callable( $order, 'get_order_number' ) ) { + return $order->get_order_number(); + } else { + return $order->get_id(); + } + } + + /** + * @return true|\WP_Error + */ + public function next() { + $args = $this->args; + $results = Queue::query( $args ); + $orders_processed = 0; + $tax_data = $this->get_temporary_result(); + $supports_refunds = in_array( 'shop_order_refund', $args['order_types'], true ); + + Package::extended_log( sprintf( '%d applicable orders found', count( $results ) ) ); + + if ( ! empty( $results ) ) { + foreach ( $results as $result ) { + if ( $order = wc_get_order( $result->ID ) ) { + $forced_parent_order = false; + + /** + * Query refund's parent order as the refund does not contain enough data (e.g. billing_country) + */ + if ( $order->get_parent_id() > 0 ) { + $forced_parent_order = wc_get_order( $order->get_parent_id() ); + + if ( ! $forced_parent_order ) { + continue; + } + + Package::extended_log( sprintf( 'Parent order: %s', $this->get_order_number( $forced_parent_order ) ) ); + } elseif ( is_callable( array( $order, 'get_shipping_country' ) ) ) { + $forced_parent_order = $order; + } + + if ( ! $forced_parent_order ) { + continue; + } + + $taxable_country = $this->get_order_taxable_country( $forced_parent_order ); + + if ( ! $this->include_order( $forced_parent_order ) ) { + Package::extended_log( sprintf( 'Skipping order #%1$s based on taxable country %2$s, tax total: %3$s', $this->get_order_number( $order ), $taxable_country, $order->get_total_tax() ) ); + continue; + } + + $country_iso = $this->get_taxable_country_iso( $taxable_country ); + + Package::extended_log( sprintf( 'Processing order #%1$s (%2$s) based on taxable country %3$s', $this->get_order_number( $order ), $order->get_type(), $country_iso ) ); + + if ( ! isset( $tax_data[ $country_iso ] ) ) { + $tax_data[ $country_iso ] = array(); + } + + foreach ( $order->get_taxes() as $key => $tax ) { + $tax_percent = (float) Helper::get_tax_rate_percent( $tax->get_rate_id(), $forced_parent_order ); + $tax_total = (float) $tax->get_tax_total() + (float) $tax->get_shipping_tax_total(); + + /** + * Do only remove refunded tax total in case this query does not explicitly support refunds (e.g. observers) + */ + if ( ! $supports_refunds ) { + $refunded = (float) $forced_parent_order->get_total_tax_refunded_by_rate_id( $tax->get_rate_id() ); + $tax_total = $tax_total - $refunded; + + Package::extended_log( sprintf( 'Refunded tax %1$s = %2$s', $tax_percent, $refunded ) ); + } + + if ( $tax_percent <= 0 || 0.0 === $tax_total ) { + if ( $tax_percent <= 0 ) { + Package::extended_log( sprintf( 'Skipping order due to missing tax percentage' ) ); + } + + if ( 0.0 === $tax_total ) { + Package::extended_log( sprintf( 'Skipping order due to tax total = 0' ) ); + } + + continue; + } + + if ( ! isset( $tax_data[ $country_iso ][ "$tax_percent" ] ) ) { + $tax_data[ $country_iso ][ "$tax_percent" ] = array( + 'tax_total' => 0, + 'net_total' => 0, + ); + } + + $net_total = ( $tax_total / ( (float) $tax_percent / 100 ) ); + + Package::extended_log( sprintf( 'Tax total %1$s = %2$s', $tax_percent, $tax_total ) ); + Package::extended_log( sprintf( 'Net total %1$s = %2$s', $tax_percent, $net_total ) ); + + $net_total = wc_add_number_precision( $net_total, false ); + $tax_total = wc_add_number_precision( $tax_total, false ); + + $tax_data[ $country_iso ][ "$tax_percent" ]['tax_total'] = (float) $tax_data[ $country_iso ][ "$tax_percent" ]['tax_total']; + $tax_data[ $country_iso ][ "$tax_percent" ]['tax_total'] += $tax_total; + + $tax_data[ $country_iso ][ "$tax_percent" ]['net_total'] = (float) $tax_data[ $country_iso ][ "$tax_percent" ]['net_total']; + $tax_data[ $country_iso ][ "$tax_percent" ]['net_total'] += $net_total; + + $orders_processed++; + } + } + } + + $this->args['orders_processed'] = absint( $this->args['orders_processed'] ) + $orders_processed; + + update_option( $this->get_id() . '_tmp_result', $tax_data, false ); + + return true; + } else { + return new \WP_Error( 'empty', _x( 'No orders found.', 'oss', 'woocommerce-germanized' ) ); + } + } + + /** + * @return Report + */ + public function complete() { + Package::extended_log( sprintf( 'Completed called' ) ); + + $tmp_result = $this->get_temporary_result(); + $report = new Report( $this->get_id() ); + $tax_total = 0; + $net_total = 0; + + foreach ( $tmp_result as $country => $tax_data ) { + foreach ( $tax_data as $percent => $totals ) { + $tax_total += (float) $totals['tax_total']; + $net_total += (float) $totals['net_total']; + + $report->set_country_net_total( $country, $percent, (float) wc_remove_number_precision( $totals['net_total'] ) ); + $report->set_country_tax_total( $country, $percent, (float) wc_remove_number_precision( $totals['tax_total'] ) ); + } + } + + $net_total = (float) wc_remove_number_precision( $net_total ); + $tax_total = (float) wc_remove_number_precision( $tax_total ); + + Package::extended_log( sprintf( 'Completed net total: %s', $net_total ) ); + Package::extended_log( sprintf( 'Completed tax total: %s', $tax_total ) ); + + $report->set_net_total( $net_total ); + $report->set_tax_total( $tax_total ); + $report->set_status( 'completed' ); + $report->set_version( Package::get_version() ); + $report->save(); + + return $report; + } + + protected function get_temporary_result() { + return (array) get_option( $this->get_id() . '_tmp_result', array() ); + } +} diff --git a/packages/one-stop-shop-woocommerce/src/CSVExporter.php b/packages/one-stop-shop-woocommerce/src/CSVExporter.php new file mode 100644 index 000000000..89ffa40f8 --- /dev/null +++ b/packages/one-stop-shop-woocommerce/src/CSVExporter.php @@ -0,0 +1,119 @@ +report = new Report( $id ); + $this->decimals = apply_filters( 'oss_woocommerce_csv_export_decimals', $decimals, $this ); + $this->column_names = $this->get_default_column_names(); + $this->filename = sanitize_file_name( $this->report->get_id() . '.csv' ); + } + + /** + * Return an array of columns to export. + * + * @since 3.1.0 + * @return array + */ + public function get_default_column_names() { + return apply_filters( + 'one_stop_shop_woocommerce_export_default_columns', + array( + 'country' => _x( 'Country code', 'oss', 'woocommerce-germanized' ), + 'tax_rate' => _x( 'Tax rate', 'oss', 'woocommerce-germanized' ), + 'taxable_base' => _x( 'Taxable base', 'oss', 'woocommerce-germanized' ), + 'amount' => _x( 'Amount', 'oss', 'woocommerce-germanized' ), + ) + ); + } + + public function get_report() { + return $this->report; + } + + public function get_decimals() { + return $this->decimals; + } + + protected function format_decimal( $value ) { + return wc_format_decimal( $value, $this->get_decimals() ); + } + + protected function format_country( $country ) { + return strtoupper( $country ); + } + + protected function get_row_data( $country, $tax_rate ) { + $row = array(); + + foreach ( array_keys( $this->get_column_names() ) as $column_id ) { + $column_id = strstr( $column_id, ':' ) ? current( explode( ':', $column_id ) ) : $column_id; + $value = ''; + + if ( 'country' === $column_id ) { + $value = $this->format_country( $country ); + } elseif ( 'tax_rate' === $column_id ) { + $value = $this->format_decimal( $tax_rate ); + } elseif ( 'taxable_base' === $column_id ) { + $value = $this->format_decimal( $this->report->get_country_net_total( $country, $tax_rate, $this->get_decimals() ) ); + } elseif ( 'amount' === $column_id ) { + $value = $this->format_decimal( $this->report->get_country_tax_total( $country, $tax_rate, $this->get_decimals() ) ); + } elseif ( is_callable( array( $this, "get_column_value_{$column_id}" ) ) ) { + $value = $this->{"get_column_value_{$column_id}"}( $country, $tax_rate ); + } else { + $value = apply_filters( "one_stop_shop_woocommerce_export_column_{$column_id}", $value, $country, $tax_rate, $this ); + } + + $row[ $column_id ] = $value; + } + + return $row; + } + + /** + * Prepare data that will be exported. + */ + public function prepare_data_to_export() { + $countries = $this->report->get_countries(); + + if ( ! empty( $countries ) ) { + foreach ( $countries as $country ) { + foreach ( $this->report->get_tax_rates_by_country( $country ) as $tax_rate ) { + $this->row_data[] = apply_filters( 'one_stop_shop_woocommerce_export_row_data', $this->get_row_data( $country, $tax_rate ), $country, $tax_rate, $this ); + } + } + } + } +} diff --git a/packages/one-stop-shop-woocommerce/src/CSVExporterBOP.php b/packages/one-stop-shop-woocommerce/src/CSVExporterBOP.php new file mode 100644 index 000000000..f832f942b --- /dev/null +++ b/packages/one-stop-shop-woocommerce/src/CSVExporterBOP.php @@ -0,0 +1,125 @@ + 'Satzart', + 'country' => 'Land des Verbrauchs', + 'tax_type' => 'Umsatzsteuertyp', + 'tax_rate' => 'Umsatzsteuersatz', + 'taxable_base' => 'Steuerbemessungsgrundlage, Nettobetrag', + 'amount' => 'Umsatzsteuerbetrag', + ) + ); + } + + protected function get_column_value_bop_type( $country, $tax_rate ) { + return apply_filters( 'one_stop_shop_woocommerce_bop_export_type', 3 ); + } + + protected function get_column_value_tax_type( $country, $tax_rate ) { + $tax_type = Helper::get_tax_type_by_country_rate( $tax_rate, $country ); + $tax_return_type = 'STANDARD'; + + switch ( $tax_type ) { + case 'reduced': + case 'greater-reduced': + case 'super-reduced': + $tax_return_type = 'REDUCED'; + break; + default: + $tax_return_type = strtoupper( $tax_type ); + break; + } + + return $tax_return_type; + } + + protected function format_country( $country ) { + $country = parent::format_country( $country ); + + if ( 'GR' === $country ) { + $country = 'EL'; + } + + return $country; + } + + /** + * Prepare data that will be exported. + */ + public function prepare_data_to_export() { + $countries = $this->report->get_countries(); + + if ( ! empty( $countries ) ) { + foreach ( $countries as $country ) { + $tax_rates = $this->report->get_tax_rates_by_country( $country ); + + if ( ! empty( $tax_rates ) ) { + $this->row_data[] = apply_filters( + 'one_stop_shop_woocommerce_export_bop_country_header_data', + array( + 'country' => $this->format_country( $country ), + 'bop_type' => 1, + ), + $country, + $this + ); + + foreach ( $tax_rates as $tax_rate ) { + $this->row_data[] = apply_filters( 'one_stop_shop_woocommerce_bop_export_row_data', $this->get_row_data( $country, $tax_rate ), $country, $tax_rate, $this ); + } + } + } + } + } + + /** + * Do the export. Prevent Woo from prepending a BOM. + */ + public function export() { + $this->prepare_data_to_export(); + $this->send_headers(); + + $csv_data = $this->export_column_headers() . $this->get_csv_data(); + + // Replace newlines with Windows-style. + $csv_data = preg_replace( '~\R~u', "\r", $csv_data ); + + $this->send_content( $csv_data ); + die(); + } + + protected function export_column_headers() { + $buffer = fopen( 'php://output', 'w' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fopen + ob_start(); + fwrite( $buffer, '#v1.1' . PHP_EOL ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fwrite + $content = ob_get_clean(); + + return $content; + } + + protected function fputcsv( $buffer, $export_row ) { + fputcsv( $buffer, $export_row, $this->get_delimiter(), "'", "\0" ); // @codingStandardsIgnoreLine + } +} diff --git a/packages/one-stop-shop-woocommerce/src/DeliveryThresholdEmailNotification.php b/packages/one-stop-shop-woocommerce/src/DeliveryThresholdEmailNotification.php new file mode 100644 index 000000000..39d7ffc80 --- /dev/null +++ b/packages/one-stop-shop-woocommerce/src/DeliveryThresholdEmailNotification.php @@ -0,0 +1,113 @@ +template_base = Package::get_path() . '/templates/'; + $this->id = 'oss_delivery_threshold_email_notification'; + $this->title = _x( 'OSS Delivery Threshold Notification', 'oss', 'woocommerce-germanized' ); + $this->description = _x( 'This email notifies shop owners in case the delivery threshold (OSS) is close to being reached.', 'oss', 'woocommerce-germanized' ); + $this->template_html = 'emails/admin-delivery-threshold.php'; + $this->template_plain = 'emails/plain/admin-delivery-threshold.php'; + $this->customer_email = false; + + parent::__construct(); + + // Other settings. + $this->recipient = $this->get_option( 'recipient', get_option( 'admin_email' ) ); + } + + /** + * Get email subject. + * + * @since 3.1.0 + * @return string + */ + public function get_default_subject() { + return _x( '[{site_title}]: OSS delivery threshold reached', 'oss', 'woocommerce-germanized' ); + } + + /** + * Get email heading. + * + * @since 3.1.0 + * @return string + */ + public function get_default_heading() { + return _x( 'OSS delivery threshold reached', 'oss', 'woocommerce-germanized' ); + } + + /** + * Get content html. + * + * @return string + */ + public function get_content_html() { + return wc_get_template_html( + $this->template_html, + array( + 'report' => $this->object, + 'email_heading' => $this->get_heading(), + 'additional_content' => $this->get_additional_content(), + 'sent_to_admin' => true, + 'plain_text' => false, + 'email' => $this, + ), + '', + $this->template_base + ); + } + + /** + * Get content plain. + * + * @return string + */ + public function get_content_plain() { + return wc_get_template_html( + $this->template_plain, + array( + 'report' => $this->object, + 'email_heading' => $this->get_heading(), + 'additional_content' => $this->get_additional_content(), + 'sent_to_admin' => true, + 'plain_text' => true, + 'email' => $this, + ), + '', + $this->template_base + ); + } + + /** + * Trigger the sending of this email. + * + * @param Report $report + */ + public function trigger( $report ) { + $this->object = $report; + + $success = $this->send( + $this->get_recipient(), + $this->get_subject(), + $this->get_content(), + $this->get_headers(), + $this->get_attachments() + ); + + if ( $success ) { + update_option( 'oss_woocommerce_notification_sent_' . $report->get_date_start()->format( 'Y' ), 'yes', false ); + } + } +} diff --git a/packages/one-stop-shop-woocommerce/src/DeliveryThresholdWarning.php b/packages/one-stop-shop-woocommerce/src/DeliveryThresholdWarning.php new file mode 100644 index 000000000..59d023aa8 --- /dev/null +++ b/packages/one-stop-shop-woocommerce/src/DeliveryThresholdWarning.php @@ -0,0 +1,40 @@ + '', + 'title' => _x( 'See details', 'oss', 'woocommerce-germanized' ), + 'url' => Settings::get_settings_url(), + 'is_primary' => true, + ), + ), + parent::get_actions() + ); + } + + public static function get_content() { + return Admin::get_threshold_notice_content(); + } + + public static function get_title() { + return Admin::get_threshold_notice_title(); + } + + public static function is_enabled() { + $is_enabled = parent::is_enabled(); + + return $is_enabled && Package::enable_auto_observer() && Package::observer_report_needs_notification(); + } + + public static function get_id() { + return 'delivery-threshold-warning-' . date( 'Y' ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date + } +} diff --git a/packages/one-stop-shop-woocommerce/src/Install.php b/packages/one-stop-shop-woocommerce/src/Install.php new file mode 100644 index 000000000..1aae1b7c3 --- /dev/null +++ b/packages/one-stop-shop-woocommerce/src/Install.php @@ -0,0 +1,41 @@ +get_status() ) { + $report->delete(); + } + } + } + } + + /** + * Make sure there is only one observer running at a time. + */ + foreach ( $running as $k => $report_id ) { + if ( in_array( $report_id, $running_observers, true ) && $report_id !== $has_running_observer ) { + if ( $report = self::get_report( $report_id ) ) { + $report->delete(); + } + + unset( $running[ $k ] ); + } + } + + $running = array_values( $running ); + + update_option( 'oss_woocommerce_reports_running', $running, false ); + Queue::clear_cache(); + + $observer_reports = self::get_reports( + array( + 'type' => 'observer', + 'include_observer' => true, + ) + ); + + foreach ( $observer_reports as $observer ) { + if ( ! self::enable_auto_observer() ) { + /** + * Delete observers in case observing was disabled. + */ + $observer->delete(); + } else { + /* + * Do not delete running observers (which are orphans by design) + */ + if ( $observer->get_id() === $has_running_observer ) { + continue; + } + + $year = $observer->get_date_start()->format( 'Y' ); + + /** + * Delete orphan observer reports (reports not linked as a main observer for a certain year). + */ + if ( get_option( 'oss_woocommerce_observer_report_' . $year ) !== $observer->get_id() ) { + $observer->delete(); + } + } + } + + /** + * In case the current observer report does not exist - delete the option + */ + if ( self::enable_auto_observer() ) { + $year = date( 'Y' ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date + $report_id = get_option( 'oss_woocommerce_observer_report_' . $year ); + + if ( ! empty( $report_id ) ) { + if ( ! self::get_report( $report_id ) ) { + delete_option( 'oss_woocommerce_observer_report_' . $year ); + } + } + } + } + + public static function dependency_notice() { + ?> +

+ get_net_total(); + } + + $total_left = self::get_delivery_threshold() - $net_total; + + if ( $total_left <= 0 ) { + $total_left = 0; + } + + return $total_left; + } + + /** + * @param null $year + * + * @return false|Report + */ + public static function get_completed_observer_report( $year = null ) { + $observer_report = self::get_observer_report( $year ); + + if ( ! $observer_report || 'completed' !== $observer_report->get_status() ) { + return false; + } + + return $observer_report; + } + + /** + * @param null $year + * + * @return false|Report + */ + public static function get_observer_report( $year = null ) { + if ( is_null( $year ) ) { + $year = date( 'Y' ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date + } + + $report_id = get_option( 'oss_woocommerce_observer_report_' . $year ); + $report = false; + + if ( ! empty( $report_id ) ) { + $report = self::get_report( $report_id ); + } + + return $report; + } + + public static function observer_report_is_outdated() { + $is_outdated = true; + + if ( $observer = self::get_observer_report() ) { + $date_end = $observer->get_date_end(); + $now = new \WC_DateTime(); + + $diff = $now->diff( $date_end ); + + if ( $diff->days <= 1 ) { + $is_outdated = false; + } + } + + return $is_outdated; + } + + public static function string_to_datetime( $time_string ) { + if ( is_string( $time_string ) && ! is_numeric( $time_string ) ) { + $time_string = strtotime( $time_string ); + } + + $date_time = $time_string; + + if ( is_numeric( $date_time ) ) { + $date_time = new \WC_DateTime( "@{$date_time}", new \DateTimeZone( 'UTC' ) ); + } + + if ( ! is_a( $date_time, 'WC_DateTime' ) ) { + return null; + } + + return $date_time; + } + + /** + * @param $id + * + * @return false|Report + */ + public static function get_report( $id ) { + $report = new Report( $id ); + + if ( $report->exists() ) { + return $report; + } + + return false; + } + + public static function get_report_id( $parts ) { + $parts = wp_parse_args( + $parts, + array( + 'type' => 'daily', + 'date_start' => date( 'Y-m-d' ), // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date + 'date_end' => date( 'Y-m-d' ), // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date + ) + ); + + if ( is_a( $parts['date_start'], 'WC_DateTime' ) ) { + $parts['date_start'] = $parts['date_start']->format( 'Y-m-d' ); + } + + if ( is_a( $parts['date_end'], 'WC_DateTime' ) ) { + $parts['date_end'] = $parts['date_end']->format( 'Y-m-d' ); + } + + return 'oss_' . $parts['type'] . '_report_' . $parts['date_start'] . '_' . $parts['date_end']; + } + + public static function get_report_data( $id ) { + $id_parts = explode( '_', $id ); + $data = array( + 'id' => $id, + 'type' => $id_parts[1], + 'date_start' => self::string_to_datetime( $id_parts[3] ), + 'date_end' => self::string_to_datetime( $id_parts[4] ), + ); + + return $data; + } + + public static function get_report_title( $id ) { + $args = self::get_report_data( $id ); + $title = _x( 'Report', 'oss', 'woocommerce-germanized' ); + + if ( 'quarterly' === $args['type'] ) { + $date_start = $args['date_start']; + $quarter = 1; + $month_num = (int) $date_start->date_i18n( 'n' ); + + if ( 4 === $month_num ) { + $quarter = 2; + } elseif ( 7 === $month_num ) { + $quarter = 3; + } elseif ( 10 === $month_num ) { + $quarter = 4; + } + + $title = sprintf( _x( 'Q%1$s/%2$s', 'oss', 'woocommerce-germanized' ), $quarter, $date_start->date_i18n( 'Y' ) ); + } elseif ( 'monthly' === $args['type'] ) { + $date_start = $args['date_start']; + $month_num = $date_start->date_i18n( 'm' ); + + $title = sprintf( _x( '%1$s/%2$s', 'oss', 'woocommerce-germanized' ), $month_num, $date_start->date_i18n( 'Y' ) ); + } elseif ( 'yearly' === $args['type'] ) { + $date_start = $args['date_start']; + + $title = sprintf( _x( '%1$s', 'oss', 'woocommerce-germanized' ), $date_start->date_i18n( 'Y' ) ); // phpcs:ignore WordPress.WP.I18n.NoEmptyStrings + } elseif ( 'custom' === $args['type'] ) { + $date_start = $args['date_start']; + $date_end = $args['date_end']; + + $title = sprintf( _x( '%1$s - %2$s', 'oss', 'woocommerce-germanized' ), $date_start->date_i18n( 'Y-m-d' ), $date_end->date_i18n( 'Y-m-d' ) ); + } elseif ( 'observer' === $args['type'] ) { + $date_start = $args['date_start']; + $date_end = $args['date_end']; + + $title = sprintf( _x( 'Observer %1$s', 'oss', 'woocommerce-germanized' ), $date_start->date_i18n( 'Y' ) ); + } + + return $title; + } + + /** + * @param Report $report + */ + public static function remove_report( $report ) { + $reports_available = self::get_report_ids(); + + if ( in_array( $report->get_id(), $reports_available[ $report->get_type() ], true ) ) { + $reports_available[ $report->get_type() ] = array_diff( $reports_available[ $report->get_type() ], array( $report->get_id() ) ); + + update_option( 'oss_woocommerce_reports', $reports_available, false ); + + /** + * Force non-cached option + */ + wp_cache_delete( 'oss_woocommerce_reports', 'options' ); + } + } + + /** + * @param array $args + * + * @return Report[] + */ + public static function get_reports( $args = array() ) { + $args = wp_parse_args( + $args, + array( + 'type' => '', + 'limit' => -1, + 'offset' => 0, + 'orderby' => 'date_start', + 'include_observer' => false, + ) + ); + + $ids = self::get_report_ids( $args['include_observer'] ); + + if ( ! empty( $args['type'] ) ) { + $report_ids = array_key_exists( $args['type'], $ids ) ? $ids[ $args['type'] ] : array(); + } else { + $report_ids = array_merge( ...array_values( $ids ) ); + } + + $reports_sorted = array(); + + foreach ( $report_ids as $id ) { + $reports_sorted[] = self::get_report_data( $id ); + } + + if ( array_key_exists( $args['orderby'], array( 'date_start', 'date_end' ) ) ) { + usort( + $reports_sorted, + function( $a, $b ) use ( $args ) { + if ( $a[ $args['orderby'] ] === $b[ $args['orderby'] ] ) { + return 0; + } + + return $a[ $args['orderby'] ] < $b[ $args['orderby'] ] ? -1 : 1; + } + ); + } + + if ( -1 !== $args['limit'] ) { + $reports_sorted = array_slice( $reports_sorted, $args['offset'], $args['limit'] ); + } + + $reports = array(); + + foreach ( $reports_sorted as $data ) { + if ( $report = self::get_report( $data['id'] ) ) { + $reports[] = $report; + } + } + + return $reports; + } + + public static function clear_caches() { + delete_transient( 'oss_reports_counts' ); + wp_cache_delete( 'oss_woocommerce_reports', 'options' ); + } + + public static function get_report_counts() { + $types = array_keys( self::get_available_report_types( true ) ); + $cache_key = 'oss_reports_counts'; + $counts = get_transient( $cache_key ); + + if ( false === $counts ) { + $counts = array(); + + foreach ( $types as $type ) { + $counts[ $type ] = 0; + } + + foreach ( self::get_reports( array( 'include_observer' => true ) ) as $report ) { + if ( ! array_key_exists( $report->get_type(), $counts ) ) { + continue; + } + + $counts[ $report->get_type() ] += 1; + } + + set_transient( $cache_key, $counts ); + } + + return (array) $counts; + } + + public static function load_plugin_textdomain() { + if ( function_exists( 'determine_locale' ) ) { + $locale = determine_locale(); + } else { + // @todo Remove when start supporting WP 5.0 or later. + $locale = is_admin() ? get_user_locale() : get_locale(); + } + + $locale = apply_filters( 'plugin_locale', $locale, 'woocommerce-germanized' ); + + unload_textdomain( 'oss-woocommerce' ); + load_textdomain( 'oss-woocommerce', trailingslashit( WP_LANG_DIR ) . 'oss-woocommerce/oss-woocommerce-' . $locale . '.mo' ); + load_plugin_textdomain( 'oss-woocommerce', false, plugin_basename( dirname( __FILE__ ) ) . '/i18n/languages/' ); + } + + public static function register_emails( $emails ) { + $mails = array( + '\Vendidero\OneStopShop\DeliveryThresholdEmailNotification', + ); + + foreach ( $mails as $mail ) { + $emails[ self::sanitize_email_class( $mail ) ] = new $mail(); + } + + return $emails; + } + + protected static function sanitize_email_class( $class ) { + return 'oss_woocommerce_' . sanitize_key( str_replace( __NAMESPACE__ . '\\', '', $class ) ); + } + + public static function observer_report_needs_notification() { + $needs_notification = false; + + if ( $report = self::get_observer_report() ) { + $net_total = $report->get_net_total(); + $threshold = self::get_delivery_notification_threshold(); + + if ( $net_total >= $threshold ) { + $needs_notification = true; + } + } + + return apply_filters( 'oss_woocommerce_observer_report_needs_notification', $needs_notification ); + } + + /** + * @param Report $observer_report + */ + public static function maybe_send_notification( $observer_report ) { + if ( self::observer_report_needs_notification() ) { + if ( 'yes' !== get_option( 'oss_woocommerce_notification_sent_' . $observer_report->get_date_start()->format( 'Y' ) ) ) { + $mails = WC()->mailer()->get_emails(); + $mail = self::sanitize_email_class( '\Vendidero\OneStopShop\DeliveryThresholdEmailNotification' ); + + if ( isset( $mails[ $mail ] ) ) { + $mails[ $mail ]->trigger( $observer_report ); + } + } + } + } + + /** + * Let the observer date back 7 days to make sure most of the orders + * have already been processed (e.g. received payment etc) to reduce the chance of missing out on orders. + * + * @return int + */ + public static function get_observer_backdating_days() { + return 7; + } + + public static function update_observer_report() { + if ( self::enable_auto_observer() ) { + /** + * Delete observer reports with missing versions to make sure the report + * is re-created with the new backdating functionality. + */ + if ( $report = self::get_observer_report() ) { + if ( '' === $report->get_version() ) { + $report->delete(); + } + } + + $days = (int) self::get_observer_backdating_days(); + + $date_start = new \WC_DateTime(); + $date_start->modify( "-{$days} day" . ( $days > 1 ? 's' : '' ) ); + + Queue::start( 'observer', $date_start ); + } + } + + public static function setup_recurring_actions() { + if ( $queue = Queue::get_queue() ) { + + // Schedule once per day at 2:00 + if ( null === $queue->get_next( 'oss_woocommerce_daily_cleanup', array(), 'oss_woocommerce' ) ) { + $timestamp = strtotime( 'tomorrow midnight' ); + $date = new \WC_DateTime(); + + $date->setTimestamp( $timestamp ); + $date->modify( '+2 hours' ); + + $queue->cancel_all( 'oss_woocommerce_daily_cleanup', array(), 'oss_woocommerce' ); + $queue->schedule_recurring( $date->getTimestamp(), DAY_IN_SECONDS, 'oss_woocommerce_daily_cleanup', array(), 'oss_woocommerce' ); + } + + if ( self::enable_auto_observer() ) { + // Schedule once per day at 3:00 + if ( null === $queue->get_next( 'oss_woocommerce_daily_observer', array(), 'oss_woocommerce' ) ) { + $timestamp = strtotime( 'tomorrow midnight' ); + $date = new \WC_DateTime(); + + $date->setTimestamp( $timestamp ); + $date->modify( '+3 hours' ); + + $queue->cancel_all( 'oss_woocommerce_daily_observer', array(), 'oss_woocommerce' ); + $queue->schedule_recurring( $date->getTimestamp(), DAY_IN_SECONDS, 'oss_woocommerce_daily_observer', array(), 'oss_woocommerce' ); + } + } else { + $queue->cancel( 'oss_woocommerce_daily_observer', array(), 'oss_woocommerce' ); + } + } + } + + public static function get_available_report_types( $include_observer = false ) { + $types = array( + 'quarterly' => _x( 'Quarterly', 'oss', 'woocommerce-germanized' ), + 'yearly' => _x( 'Yearly', 'oss', 'woocommerce-germanized' ), + 'monthly' => _x( 'Monthly', 'oss', 'woocommerce-germanized' ), + 'custom' => _x( 'Custom', 'oss', 'woocommerce-germanized' ), + ); + + if ( $include_observer ) { + $types['observer'] = _x( 'Observer', 'oss', 'woocommerce-germanized' ); + } + + return $types; + } + + public static function get_type_title( $type ) { + $types = self::get_available_report_types( true ); + + return array_key_exists( $type, $types ) ? $types[ $type ] : ''; + } + + public static function get_report_statuses() { + return array( + 'pending' => _x( 'Pending', 'oss', 'woocommerce-germanized' ), + 'completed' => _x( 'Completed', 'oss', 'woocommerce-germanized' ), + 'failed' => _x( 'Failed', 'oss', 'woocommerce-germanized' ), + ); + } + + public static function get_report_status_title( $status ) { + $statuses = self::get_report_statuses(); + + return array_key_exists( $status, $statuses ) ? $statuses[ $status ] : ''; + } + + public static function has_dependencies() { + return ( class_exists( 'WooCommerce' ) ); + } + + public static function install() { + self::init(); + Install::install(); + } + + public static function deactivate() { + if ( self::has_dependencies() && Admin::supports_wc_admin() ) { + foreach ( Admin::get_notes() as $oss_note ) { + Admin::delete_wc_admin_note( $oss_note ); + } + } + } + + public static function install_integration() { + self::install(); + } + + public static function is_integration() { + $gzd_installed = class_exists( 'WooCommerce_Germanized' ); + $gzd_version = get_option( 'woocommerce_gzd_version', '1.0' ); + + return $gzd_installed && version_compare( $gzd_version, '3.5.0', '>=' ) ? true : false; + } + + /** + * Return the version of the package. + * + * @return string + */ + public static function get_version() { + return self::VERSION; + } + + /** + * Return the path to the package. + * + * @return string + */ + public static function get_path() { + return dirname( __DIR__ ); + } + + /** + * Return the path to the package. + * + * @return string + */ + public static function get_url() { + return plugins_url( '', __DIR__ ); + } + + public static function get_assets_url() { + return self::get_url() . '/assets'; + } + + private static function define_constant( $name, $value ) { + if ( ! defined( $name ) ) { + define( $name, $value ); + } + } + + public static function log( $message, $type = 'info' ) { + $logger = wc_get_logger(); + + if ( ! $logger || ! apply_filters( 'oss_woocommerce_enable_logging', true ) ) { + return; + } + + if ( ! is_callable( array( $logger, $type ) ) ) { + $type = 'info'; + } + + $logger->{$type}( $message, array( 'source' => 'one-stop-shop-woocommerce' ) ); + } + + public static function extended_log( $message, $type = 'info' ) { + if ( apply_filters( 'oss_woocommerce_enable_extended_logging', ( defined( 'WP_DEBUG' ) && WP_DEBUG ) ) ) { + self::log( $message, $type ); + } + } +} diff --git a/packages/one-stop-shop-woocommerce/src/Queue.php b/packages/one-stop-shop-woocommerce/src/Queue.php new file mode 100644 index 000000000..bbec8efbb --- /dev/null +++ b/packages/one-stop-shop-woocommerce/src/Queue.php @@ -0,0 +1,514 @@ +diff( $args['end'] ); + + /** + * Except observers, all new queries treat refunds separately + */ + if ( 'observer' !== $type ) { + $args['order_types'] = array( + 'shop_order', + 'shop_order_refund', + ); + } + + // Add version + $args['version'] = Package::get_version(); + + $generator = new AsyncReportGenerator( $type, $args ); + $queue_args = $generator->get_args(); + $queue = self::get_queue(); + + self::cancel( $generator->get_id() ); + + $report = $generator->start(); + + if ( is_a( $report, '\Vendidero\OneStopShop\Report' ) && $report->exists() ) { + Package::log( sprintf( 'Starting new %1$s', $report->get_title() ) ); + Package::extended_log( sprintf( 'Default report arguments: %s', wc_print_r( $queue_args, true ) ) ); + + $queue->schedule_single( + time() + 10, + 'oss_woocommerce_' . $generator->get_id(), + array( 'args' => $queue_args ), + 'oss_woocommerce' + ); + + $running = self::get_reports_running(); + + if ( ! in_array( $generator->get_id(), $running, true ) ) { + $running[] = $generator->get_id(); + } + + update_option( 'oss_woocommerce_reports_running', $running, false ); + self::clear_cache(); + + return $generator->get_id(); + } + + return false; + } + + public static function clear_cache() { + wp_cache_delete( 'oss_woocommerce_reports_running', 'options' ); + } + + public static function get_queue_details( $report_id ) { + $details = array( + 'next_date' => null, + 'link' => admin_url( 'admin.php?page=wc-status&tab=action-scheduler&s=' . esc_attr( $report_id ) . '&status=pending' ), + 'order_count' => 0, + 'has_action' => false, + 'is_finished' => false, + 'action' => false, + ); + + if ( $queue = self::get_queue() ) { + + if ( $next_date = $queue->get_next( 'oss_woocommerce_' . $report_id ) ) { + $details['next_date'] = $next_date; + } + + $search_args = array( + 'hook' => 'oss_woocommerce_' . $report_id, + 'status' => \ActionScheduler_Store::STATUS_RUNNING, + 'order' => 'DESC', + 'per_page' => 1, + ); + + $results = $queue->search( $search_args ); + + /** + * Search for pending as fallback + */ + if ( empty( $results ) ) { + $search_args['status'] = \ActionScheduler_Store::STATUS_PENDING; + $results = $queue->search( $search_args ); + } + + /** + * Last resort: Search for completed (e.g. if no pending and no running are found - must have been completed) + */ + if ( empty( $results ) ) { + $search_args['status'] = \ActionScheduler_Store::STATUS_COMPLETE; + $results = $queue->search( $search_args ); + } + + if ( ! empty( $results ) ) { + $action = array_values( $results )[0]; + $args = $action->get_args(); + $processed = isset( $args['args']['orders_processed'] ) ? (int) $args['args']['orders_processed'] : 0; + + $details['order_count'] = absint( $processed ); + $details['has_action'] = true; + $details['action'] = $action; + $details['is_finished'] = $action->is_finished(); + } + } + + return $details; + } + + public static function get_batch_size() { + return apply_filters( 'oss_woocommerce_report_batch_size', 25 ); + } + + public static function use_date_paid() { + $use_date_paid = 'date_paid' === get_option( 'oss_report_date_type', 'date_paid' ); + + return apply_filters( 'oss_woocommerce_report_use_date_paid', $use_date_paid ); + } + + public static function get_order_statuses() { + $statuses = array_keys( wc_get_order_statuses() ); + $statuses = array_diff( $statuses, array( 'wc-cancelled', 'wc-failed' ) ); + + if ( self::use_date_paid() ) { + $statuses = array_diff( $statuses, array( 'wc-pending' ) ); + } + + return apply_filters( 'oss_woocommerce_valid_order_statuses', $statuses ); + } + + public static function build_query( $args ) { + global $wpdb; + + $joins = array( + "LEFT JOIN {$wpdb->postmeta} AS mt1 ON {$wpdb->posts}.ID = mt1.post_id AND (mt1.meta_key = '_shipping_country' OR mt1.meta_key = '_billing_country')", + ); + + $taxable_countries_in = self::generate_in_query_sql( Helper::get_non_base_eu_countries( true ) ); + $post_status_in = self::generate_in_query_sql( $args['status'] ); + $post_type_in = self::generate_in_query_sql( isset( $args['order_types'] ) ? (array) $args['order_types'] : array( 'shop_order' ) ); + $where_country_sql = "mt1.meta_value IN {$taxable_countries_in}"; + + if ( in_array( 'shop_order_refund', $args['order_types'], true ) ) { + $joins[] = "LEFT JOIN {$wpdb->postmeta} AS mt1_parent ON {$wpdb->posts}.post_parent = mt1_parent.post_id AND (mt1_parent.meta_key = '_shipping_country' OR mt1_parent.meta_key = '_billing_country')"; + $where_country_sql = "( {$wpdb->posts}.post_parent > 0 AND (mt1_parent.meta_value IN {$taxable_countries_in}) ) OR ( mt1.meta_value IN {$taxable_countries_in} )"; + } + + $where_date_sql = $wpdb->prepare( "{$wpdb->posts}.post_date >= %s AND {$wpdb->posts}.post_date <= %s", $args['start'], $args['end'] ); + + if ( 'date_paid' === $args['date_field'] ) { + /** + * Add one day to the end date to capture timestamps (including time data) in between + */ + $end_adjusted = strtotime( $args['end'] ) + DAY_IN_SECONDS; + + /** + * Use a max end date to limit potential query results in case date_paid meta field is used. + * This way we will only register payments made max 2 month after the order created date. + */ + $max_end = new \WC_DateTime( $args['end'] ); + $max_end->modify( '+2 months' ); + + $joins[] = "LEFT JOIN {$wpdb->postmeta} AS mt3 ON ( {$wpdb->posts}.ID = mt3.post_id AND mt3.meta_key = '_date_paid' )"; + + $where_date_sql = $wpdb->prepare( + "( {$wpdb->posts}.post_date >= %s AND {$wpdb->posts}.post_date <= %s ) AND NOT mt3.post_id IS NULL AND ( + mt3.meta_key = '_date_paid' AND mt3.meta_value >= %s AND mt3.meta_value <= %s + ) OR {$wpdb->posts}.post_parent > 0 AND ( + {$wpdb->posts}.post_date >= %s AND {$wpdb->posts}.post_date <= %s + )", + $args['start'], + $max_end->format( 'Y-m-d' ), + strtotime( $args['start'] ), + $end_adjusted, + $args['start'], + $args['end'] + ); + } + + $join_sql = implode( ' ', $joins ); + + // @codingStandardsIgnoreStart + $sql = $wpdb->prepare( + " + SELECT {$wpdb->posts}.* FROM {$wpdb->posts} + $join_sql + WHERE 1=1 + AND ( {$wpdb->posts}.post_type IN {$post_type_in} ) AND ( {$wpdb->posts}.post_status IN {$post_status_in} ) AND ( {$where_date_sql} ) + AND ( {$where_country_sql} ) + GROUP BY {$wpdb->posts}.ID + ORDER BY {$wpdb->posts}.post_date ASC + LIMIT %d, %d", + $args['offset'], + $args['limit'] + ); + // @codingStandardsIgnoreEnd + + return $sql; + } + + private static function generate_in_query_sql( $values ) { + global $wpdb; + + $in_query = array(); + + foreach ( $values as $value ) { + $in_query[] = $wpdb->prepare( "'%s'", $value ); // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.QuotedSimplePlaceholder + } + + return '(' . implode( ',', $in_query ) . ')'; + } + + public static function query( $args ) { + global $wpdb; + + $query = self::build_query( $args ); + + Package::extended_log( sprintf( 'Building new query: %s', wc_print_r( $args, true ) ) ); + Package::extended_log( $query ); + + return $wpdb->get_results( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + } + + public static function cancel( $id ) { + $data = Package::get_report_data( $id ); + $generator = new AsyncReportGenerator( $data['type'], $data ); + $queue = self::get_queue(); + $running = self::get_reports_running(); + + if ( self::is_running( $id ) ) { + $running = array_diff( $running, array( $id ) ); + Package::log( sprintf( 'Cancelled %s', Package::get_report_title( $id ) ) ); + + update_option( 'oss_woocommerce_reports_running', $running, false ); + self::clear_cache(); + $generator->delete(); + } + + /** + * Cancel outstanding events and queue new. + */ + $queue->cancel_all( 'oss_woocommerce_' . $id ); + } + + public static function get_queue() { + return function_exists( 'WC' ) ? WC()->queue() : false; + } + + public static function is_running( $id ) { + $running = self::get_reports_running(); + + if ( in_array( $id, $running, true ) && self::get_queue()->get_next( 'oss_woocommerce_' . $id ) ) { + return true; + } + + return false; + } + + public static function next( $type, $args ) { + /** + * Older versions didn't include refunds as separate orders + */ + if ( ! isset( $args['order_types'] ) ) { + $args['order_types'] = array( 'shop_order' ); + } + + $generator = new AsyncReportGenerator( $type, $args ); + $result = $generator->next(); + $is_empty = false; + $queue = self::get_queue(); + + if ( is_wp_error( $result ) ) { + $is_empty = $result->get_error_message( 'empty' ); + } + + if ( ! $is_empty ) { + $new_args = $generator->get_args(); + + // Increase offset + $new_args['offset'] = (int) $new_args['offset'] + (int) $new_args['limit']; + + $queue->cancel_all( 'oss_woocommerce_' . $generator->get_id() ); + + Package::extended_log( sprintf( 'Starting new queue: %s', wc_print_r( $new_args, true ) ) ); + + $queue->schedule_single( + time() + 10, + 'oss_woocommerce_' . $generator->get_id(), + array( 'args' => $new_args ), + 'oss_woocommerce' + ); + } else { + self::complete( $generator ); + } + } + + /** + * @param AsyncReportGenerator $generator + */ + public static function complete( $generator ) { + $queue = self::get_queue(); + $type = $generator->get_type(); + + /** + * Cancel outstanding events. + */ + $queue->cancel_all( 'oss_woocommerce_' . $generator->get_id() ); + + $report = $generator->complete(); + $status = 'failed'; + + if ( is_a( $report, '\Vendidero\OneStopShop\Report' ) && $report->exists() ) { + $status = 'completed'; + } + + Package::log( sprintf( 'Completed %1$s. Status: %2$s', $report->get_title(), $status ) ); + + self::maybe_stop_report( $report->get_id() ); + + if ( 'observer' === $report->get_type() ) { + self::update_observer( $report ); + } + } + + /** + * @param Report $report + */ + protected static function update_observer( $report ) { + $end = $report->get_date_end(); + $year = $end->date( 'Y' ); + + if ( ! $observer_report = Package::get_observer_report( $year ) ) { + $observer_report = $report; + } else { + $observer_report->set_net_total( $observer_report->get_net_total( false ) + $report->get_net_total( false ) ); + $observer_report->set_tax_total( $observer_report->get_tax_total( false ) + $report->get_tax_total( false ) ); + + foreach ( $report->get_countries() as $country ) { + foreach ( $report->get_tax_rates_by_country( $country ) as $tax_rate ) { + $observer_report->set_country_tax_total( $country, $tax_rate, ( $observer_report->get_country_tax_total( $country, $tax_rate, false ) + $report->get_country_tax_total( $country, $tax_rate, false ) ) ); + $observer_report->set_country_net_total( $country, $tax_rate, ( $observer_report->get_country_net_total( $country, $tax_rate, false ) + $report->get_country_net_total( $country, $tax_rate, false ) ) ); + } + } + + // Delete the old observer report + $observer_report->delete(); + } + + // Delete the tmp report + $report->delete(); + + $observer_report->set_date_requested( $report->get_date_requested() ); + + // Use the last report date as new end date + $observer_report->set_date_end( $report->get_date_end() ); + $observer_report->save(); + + update_option( 'oss_woocommerce_observer_report_' . $year, $observer_report->get_id(), false ); + + do_action( 'oss_woocommerce_updated_observer', $observer_report ); + } + + /** + * @return false|Report + */ + public static function get_running_observer() { + $report = false; + + foreach ( self::get_reports_running() as $id ) { + /** + * Make sure to return the last running observer in case more of one observer exists + * in running queue. + */ + if ( strstr( $id, 'observer_' ) ) { + $report = Package::get_report( $id ); + } + } + + return $report; + } + + public static function maybe_stop_report( $report_id ) { + $reports_running = self::get_reports_running(); + + if ( in_array( $report_id, $reports_running, true ) ) { + $reports_running = array_diff( $reports_running, array( $report_id ) ); + update_option( 'oss_woocommerce_reports_running', $reports_running, false ); + + if ( $queue = self::get_queue() ) { + $queue->cancel_all( 'oss_woocommerce_' . $report_id ); + } + + /** + * Force non-cached running option + */ + wp_cache_delete( 'oss_woocommerce_reports_running', 'options' ); + + return true; + } + + return false; + } + + public static function get_reports_running() { + return (array) get_option( 'oss_woocommerce_reports_running', array() ); + } + + public static function get_timeframe( $type, $date = null, $date_end = null ) { + $date_start = null; + $date_end = is_null( $date_end ) ? null : $date_end; + $start_indicator = is_null( $date ) ? new \WC_DateTime() : $date; + + if ( ! is_a( $start_indicator, 'WC_DateTime' ) && is_numeric( $start_indicator ) ) { + $start_indicator = new \WC_DateTime( '@' . $start_indicator ); + } + + if ( ! is_null( $date_end ) && ! is_a( $date_end, 'WC_DateTime' ) && is_numeric( $date_end ) ) { + $date_end = new \WC_DateTime( '@' . $date_end ); + } + + if ( 'quarterly' === $type ) { + $month = $start_indicator->date( 'n' ); + $quarter = (int) ceil( $month / 3 ); + $start_month = 'Jan'; + $end_month = 'Mar'; + + if ( 2 === $quarter ) { + $start_month = 'Apr'; + $end_month = 'Jun'; + } elseif ( 3 === $quarter ) { + $start_month = 'Jul'; + $end_month = 'Sep'; + } elseif ( 4 === $quarter ) { + $start_month = 'Oct'; + $end_month = 'Dec'; + } + + $date_start = new \WC_DateTime( 'first day of ' . $start_month . ' ' . $start_indicator->format( 'Y' ) . ' midnight' ); + $date_end = new \WC_DateTime( 'last day of ' . $end_month . ' ' . $start_indicator->format( 'Y' ) . ' midnight' ); + } elseif ( 'monthly' === $type ) { + $month = $start_indicator->format( 'M' ); + + $date_start = new \WC_DateTime( 'first day of ' . $month . ' ' . $start_indicator->format( 'Y' ) . ' midnight' ); + $date_end = new \WC_DateTime( 'last day of ' . $month . ' ' . $start_indicator->format( 'Y' ) . ' midnight' ); + } elseif ( 'yearly' === $type ) { + $date_end = clone $start_indicator; + $date_start = clone $start_indicator; + + $date_end->modify( 'last day of dec ' . $start_indicator->format( 'Y' ) . ' midnight' ); + $date_start->modify( 'first day of jan ' . $start_indicator->format( 'Y' ) . ' midnight' ); + } elseif ( 'observer' === $type ) { + $date_start = clone $start_indicator; + $report = Package::get_observer_report( $date_start->format( 'Y' ) ); + + if ( ! $report ) { + // Calculate starting with the first day of the current year until yesterday + $date_end = clone $date_start; + $date_start = new \WC_DateTime( 'first day of jan ' . $start_indicator->format( 'Y' ) . ' midnight' ); + } else { + // In case a report has already been generated lets do only calculate the timeframe between the end of the last report and now + $date_end = clone $date_start; + $date_end->setTime( 0, 0 ); + + $date_start = clone $report->get_date_end(); + $date_start->modify( '+1 day' ); + + if ( $date_start > $date_end ) { + $date_start = clone $date_end; + } + } + } else { + if ( is_null( $date_end ) ) { + $date_end = clone $start_indicator; + $date_end->modify( '-1 year' ); + } + + $date_start = clone $start_indicator; + } + + /** + * Always set start and end time to midnight + */ + if ( $date_start ) { + $date_start->setTime( 0, 0 ); + } + + if ( $date_end ) { + $date_end->setTime( 0, 0 ); + } + + return array( + 'start' => $date_start, + 'end' => $date_end, + ); + } +} diff --git a/packages/one-stop-shop-woocommerce/src/Report.php b/packages/one-stop-shop-woocommerce/src/Report.php new file mode 100644 index 000000000..dcf3519f0 --- /dev/null +++ b/packages/one-stop-shop-woocommerce/src/Report.php @@ -0,0 +1,330 @@ +set_id( $id ); + + if ( empty( $args ) ) { + $args = (array) get_option( $this->id . '_result', array() ); + } + + $args = wp_parse_args( + $args, + array( + 'countries' => array(), + 'totals' => array(), + 'meta' => array(), + ) + ); + + $args['totals'] = wp_parse_args( + $args['totals'], + array( + 'net_total' => 0, + 'tax_total' => 0, + ) + ); + + $args['meta'] = wp_parse_args( + $args['meta'], + array( + 'date_requested' => null, + 'status' => 'pending', + 'version' => '', + ) + ); + + $this->set_date_requested( $args['meta']['date_requested'] ); + $this->set_status( $args['meta']['status'] ); + $this->set_version( $args['meta']['version'] ); + + $this->args = $args; + } + + public function exists() { + return get_option( $this->id . '_result', false ); + } + + public function get_title() { + $title = Package::get_report_title( $this->get_id() ); + + if ( $this->get_date_requested() ) { + $title = $title . ' @ ' . $this->get_date_requested()->date_i18n(); + } + + return $title; + } + + public function get_url() { + return admin_url( 'admin.php?page=oss-reports&report=' . $this->get_id() ); + } + + public function get_type() { + return $this->type; + } + + public function set_type( $type ) { + $this->set_id_part( $type, 'type' ); + } + + public function set_id( $id ) { + $this->id = $id; + $data = Package::get_report_data( $this->id ); + $this->type = $data['type']; + $this->date_start = $data['date_start']; + $this->date_end = $data['date_end']; + } + + public function set_id_part( $value, $part = 'type' ) { + $data = Package::get_report_data( $this->id ); + $data[ $part ] = $value; + + $this->set_id( Package::get_report_id( $data ) ); + } + + public function get_id() { + return $this->id; + } + + public function get_date_start() { + return $this->date_start; + } + + public function set_date_start( $date ) { + $date = Package::string_to_datetime( $date ); + + $this->set_id_part( $date->format( 'Y-m-d' ), 'date_start' ); + } + + public function get_date_end() { + return $this->date_end; + } + + public function set_date_end( $date ) { + $date = Package::string_to_datetime( $date ); + + $this->set_id_part( $date->format( 'Y-m-d' ), 'date_end' ); + } + + public function get_status() { + return $this->args['meta']['status']; + } + + public function get_version() { + return $this->args['meta']['version']; + } + + public function set_status( $status ) { + $this->args['meta']['status'] = $status; + } + + public function set_version( $version ) { + $this->args['meta']['version'] = $version; + } + + public function get_date_requested() { + return is_null( $this->args['meta']['date_requested'] ) ? null : Package::string_to_datetime( $this->args['meta']['date_requested'] ); + } + + public function set_date_requested( $date ) { + if ( ! empty( $date ) ) { + $date = Package::string_to_datetime( $date ); + } + + $this->args['meta']['date_requested'] = is_a( $date, 'WC_DateTime' ) ? $date->date( 'Y-m-d' ) : null; + } + + public function get_tax_total( $round = true ) { + return $this->maybe_round( $this->args['totals']['tax_total'], $round ); + } + + public function get_net_total( $round = true ) { + return $this->maybe_round( $this->args['totals']['net_total'], $round ); + } + + public function set_tax_total( $total ) { + $this->args['totals']['tax_total'] = wc_format_decimal( floatval( $total ) ); + } + + public function set_net_total( $total ) { + $this->args['totals']['net_total'] = wc_format_decimal( floatval( $total ) ); + } + + public function get_countries() { + return array_keys( $this->args['countries'] ); + } + + public function reset() { + $this->args['countries'] = array(); + + $this->set_net_total( 0 ); + $this->set_tax_total( 0 ); + $this->set_date_requested( new \WC_DateTime() ); + $this->set_status( 'pending' ); + $this->set_version( Package::get_version() ); + + delete_option( $this->id . '_tmp_result' ); + } + + public function get_tax_rates_by_country( $country ) { + $tax_rates = array(); + + if ( array_key_exists( $country, $this->args['countries'] ) ) { + $tax_rates = array_keys( $this->args['countries'][ $country ] ); + } + + return $tax_rates; + } + + public function get_country_tax_total( $country, $tax_rate, $round = true ) { + $tax_total = 0; + + if ( isset( $this->args['countries'][ $country ], $this->args['countries'][ $country ][ "$tax_rate" ] ) ) { + $tax_total = $this->args['countries'][ $country ][ "$tax_rate" ]['tax_total']; + } + + return $this->maybe_round( $tax_total, $round ); + } + + protected function maybe_round( $total, $round = true ) { + $decimals = is_numeric( $round ) ? (int) $round : ''; + + return (float) wc_format_decimal( $total, $round ? $decimals : false ); + } + + public function get_country_net_total( $country, $tax_rate, $round = true ) { + $net_total = 0; + + if ( isset( $this->args['countries'][ $country ], $this->args['countries'][ $country ][ "$tax_rate" ] ) ) { + $net_total = $this->args['countries'][ $country ][ "$tax_rate" ]['net_total']; + } + + return $this->maybe_round( $net_total, $round ); + } + + public function set_country_tax_total( $country, $tax_rate, $tax_total = 0 ) { + if ( ! isset( $this->args['countries'][ $country ] ) ) { + $this->args['countries'][ $country ] = array(); + } + + if ( ! isset( $this->args['countries'][ $country ][ "$tax_rate" ] ) ) { + $this->args['countries'][ $country ][ "$tax_rate" ] = array( + 'net_total' => 0, + 'tax_total' => 0, + ); + } + + $this->args['countries'][ $country ][ "$tax_rate" ]['tax_total'] = $tax_total; + } + + public function set_country_net_total( $country, $tax_rate, $net_total = 0 ) { + if ( ! isset( $this->args['countries'][ $country ] ) ) { + $this->args['countries'][ $country ] = array(); + } + + if ( ! isset( $this->args['countries'][ $country ][ "$tax_rate" ] ) ) { + $this->args['countries'][ $country ][ "$tax_rate" ] = array( + 'net_total' => 0, + 'tax_total' => 0, + ); + } + + $this->args['countries'][ $country ][ "$tax_rate" ]['net_total'] = $net_total; + } + + public function save() { + update_option( $this->id . '_result', $this->args, false ); + + $reports_available = Package::get_report_ids(); + + if ( ! in_array( $this->get_id(), $reports_available[ $this->get_type() ], true ) ) { + // Add new report to start of the list + array_unshift( $reports_available[ $this->get_type() ], $this->get_id() ); + update_option( 'oss_woocommerce_reports', $reports_available, false ); + } + + delete_option( $this->id . '_tmp_result' ); + + Package::clear_caches(); + + return $this->id; + } + + public function delete() { + delete_option( $this->id . '_result' ); + delete_option( $this->id . '_tmp_result' ); + + Queue::maybe_stop_report( $this->get_id() ); + Package::remove_report( $this ); + + if ( 'observer' === $this->get_type() ) { + delete_option( 'oss_woocommerce_observer_report_' . $this->get_date_start()->format( 'Y' ) ); + } + + Package::clear_caches(); + + return true; + } + + public function get_export_link( $export_type = '' ) { + return add_query_arg( + array( + 'action' => 'oss_export_report', + 'export_type' => $export_type, + 'report_id' => $this->get_id(), + ), + wp_nonce_url( admin_url( 'admin-post.php' ), 'oss_export_report' ) + ); + } + + public function get_delete_link() { + return add_query_arg( + array( + 'action' => 'oss_delete_report', + 'report_id' => $this->get_id(), + ), + wp_nonce_url( admin_url( 'admin-post.php' ), 'oss_delete_report' ) + ); + } + + public function get_refresh_link() { + return add_query_arg( + array( + 'action' => 'oss_refresh_report', + 'report_id' => $this->get_id(), + ), + wp_nonce_url( admin_url( 'admin-post.php' ), 'oss_refresh_report' ) + ); + } + + public function get_cancel_link() { + return add_query_arg( + array( + 'action' => 'oss_cancel_report', + 'report_id' => $this->get_id(), + ), + wp_nonce_url( admin_url( 'admin-post.php' ), 'oss_cancel_report' ) + ); + } +} diff --git a/packages/one-stop-shop-woocommerce/src/ReportTable.php b/packages/one-stop-shop-woocommerce/src/ReportTable.php new file mode 100644 index 000000000..fa136fb37 --- /dev/null +++ b/packages/one-stop-shop-woocommerce/src/ReportTable.php @@ -0,0 +1,520 @@ + _x( 'Reports', 'oss', 'woocommerce-germanized' ), + 'singular' => _x( 'Report', 'oss', 'woocommerce-germanized' ), + 'screen' => isset( $args['screen'] ) ? $args['screen'] : null, + ) + ); + } + + public function set_default_hidden_columns( $columns, $screen ) { + if ( $this->screen->id === $screen->id ) { + $columns = array_merge( $columns, $this->get_default_hidden_columns() ); + } + + return $columns; + } + + protected function get_default_hidden_columns() { + return array(); + } + + protected function get_hook_prefix() { + return 'oss_woocommerce_admin_reports_table_'; + } + + public function enable_query_removing( $args ) { + $args = array_merge( + $args, + array( + 'changed', + 'bulk_action', + ) + ); + + return $args; + } + + /** + * Handle bulk actions. + * + * @param string $redirect_to URL to redirect to. + * @param string $action Action name. + * @param array $ids List of ids. + * @return string + */ + public function handle_bulk_actions( $action, $ids, $redirect_to ) { + $ids = array_reverse( wc_clean( $ids ) ); + $changed = 0; + + if ( 'delete' === $action ) { + foreach ( $ids as $id ) { + if ( $report = Package::get_report( $id ) ) { + if ( $report->delete() ) { + $changed++; + } + } + } + } + + $changed = apply_filters( "{$this->get_hook_prefix()}bulk_action", $changed, $action, $ids, $redirect_to, $this ); + + if ( $changed ) { + $redirect_to = add_query_arg( + array( + 'changed' => $changed, + 'ids' => join( ',', $ids ), + 'bulk_action' => $action, + ), + $redirect_to + ); + } + + return esc_url_raw( $redirect_to ); + } + + public function output_notices() { + + } + + /** + * Show confirmation message that order status changed for number of orders. + */ + public function set_bulk_notice() { + $number = isset( $_REQUEST['changed'] ) ? absint( $_REQUEST['changed'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $bulk_action = isset( $_REQUEST['bulk_action'] ) ? wc_clean( wp_unslash( $_REQUEST['bulk_action'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended + + if ( 'delete' === $bulk_action ) { + $this->add_notice( sprintf( _nx( '%d report deleted.', '%d reports deleted.', $number, 'oss', 'woocommerce-germanized' ), number_format_i18n( $number ) ) ); + } + + do_action( "{$this->get_hook_prefix()}bulk_notice", $bulk_action, $this ); + } + + public function add_notice( $message, $type = 'success' ) { + + } + + /** + * @return bool + */ + public function ajax_user_can() { + return current_user_can( 'manage_woocommerce' ); + } + + public function get_page_option() { + return 'woocommerce_page_oss_reports_per_page'; + } + + public function get_reports( $args ) { + return Package::get_reports( $args ); + } + + /** + * @global array $avail_post_stati + * @global WP_Query $wp_query + * @global int $per_page + * @global string $mode + */ + public function prepare_items() { + global $per_page; + + $per_page = $this->get_items_per_page( $this->get_page_option(), 10 ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited + $per_page = apply_filters( "{$this->get_hook_prefix()}edit_per_page", $per_page ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited + $this->counts = Package::get_report_counts(); + $paged = $this->get_pagenum(); + $report_type = isset( $_REQUEST['type'] ) ? wc_clean( wp_unslash( $_REQUEST['type'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $report_type = in_array( $report_type, array_keys( Package::get_available_report_types( true ) ), true ) ? $report_type : ''; + + $args = array( + 'limit' => $per_page, + 'paginate' => true, + 'offset' => ( $paged - 1 ) * $per_page, + 'count_total' => true, + 'type' => $report_type, + 'include_observer' => 'observer' === $report_type ? true : false, + ); + + $this->items = $this->get_reports( $args ); + + $this->set_pagination_args( + array( + 'total_items' => empty( $args['type'] ) ? array_sum( $this->counts ) : $this->counts[ $args['type'] ], + 'per_page' => $per_page, + ) + ); + } + + /** + */ + public function no_items() { + echo esc_html_x( 'No reports found', 'oss', 'woocommerce-germanized' ); + } + + /** + * Determine if the current view is the "All" view. + * + * @since 4.2.0 + * + * @return bool Whether the current view is the "All" view. + */ + protected function is_base_request() { + $vars = $_GET; // phpcs:ignore WordPress.Security.NonceVerification.Recommended + unset( $vars['paged'] ); + + if ( empty( $vars ) ) { + return true; + } + + return 1 === count( $vars ); + } + + /** + * @global array $locked_post_status This seems to be deprecated. + * @global array $avail_post_stati + * @return array + */ + protected function get_views() { + $type_links = array(); + $num_reports = $this->counts; + $total_reports = array_sum( (array) $num_reports ); + $total_reports = $total_reports - ( isset( $num_reports['observer'] ) ? $num_reports['observer'] : 0 ); + $class = ''; + $all_args = array(); + $include_observers = Package::enable_auto_observer(); + + if ( empty( $class ) && ( $this->is_base_request() || isset( $_REQUEST['all_reports'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $class = 'current'; + } + + $all_inner_html = sprintf( + _nx( + 'All (%s)', + 'All (%s)', + $total_reports, + 'oss', + 'oss-woocommerce' + ), + number_format_i18n( $total_reports ) + ); + + $type_links['all'] = $this->get_edit_link( $all_args, $all_inner_html, $class ); + + foreach ( Package::get_available_report_types( $include_observers ) as $type => $title ) { + $class = ''; + + if ( empty( $num_reports[ $type ] ) ) { + continue; + } + + if ( isset( $_REQUEST['type'] ) && $type === $_REQUEST['type'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $class = 'current'; + } + + $type_args = array( + 'type' => $type, + ); + + $type_label = sprintf( + translate_nooped_plural( _nx_noop( $title . ' (%s)', $title . ' (%s)', 'oss', 'woocommerce-germanized' ), $num_reports[ $type ] ), // phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralPlural,WordPress.WP.I18n.NonSingularStringLiteralSingle + number_format_i18n( $num_reports[ $type ] ) + ); + + $type_links[ $type ] = $this->get_edit_link( $type_args, $type_label, $class ); + } + + return $type_links; + } + + /** + * Helper to create links to edit.php with params. + * + * @since 4.4.0 + * + * @param string[] $args Associative array of URL parameters for the link. + * @param string $label Link text. + * @param string $class Optional. Class attribute. Default empty string. + * @return string The formatted link string. + */ + protected function get_edit_link( $args, $label, $class = '' ) { + $url = add_query_arg( $args, $this->get_main_page() ); + + $class_html = $aria_current = ''; + if ( ! empty( $class ) ) { + $class_html = sprintf( + ' class="%s"', + esc_attr( $class ) + ); + + if ( 'current' === $class ) { + $aria_current = ' aria-current="page"'; + } + } + + return sprintf( + '%s', + esc_url( $url ), + $class_html, + $aria_current, + $label + ); + } + + /** + * @return string + */ + public function current_action() { + if ( isset( $_REQUEST['delete_all'] ) || isset( $_REQUEST['delete_all2'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + return 'delete_all'; + } + + return parent::current_action(); + } + + /** + * @param string $which + */ + protected function extra_tablenav( $which ) { + ?> +
+ render_filters(); + do_action( "{$this->get_hook_prefix()}filters", $which ); + $output = ob_get_clean(); + + if ( ! empty( $output ) ) { + echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + + submit_button( _x( 'Filter', 'oss', 'woocommerce-germanized' ), '', 'filter_action', false, array( 'id' => 'oss-filter-submit' ) ); + } + } + ?> +
+ '; + $columns['title'] = _x( 'Title', 'oss', 'woocommerce-germanized' ); + $columns['date_start'] = _x( 'Start', 'oss', 'woocommerce-germanized' ); + $columns['date_end'] = _x( 'End', 'oss', 'woocommerce-germanized' ); + $columns['net_total'] = _x( 'Net total', 'oss', 'woocommerce-germanized' ); + $columns['tax_total'] = _x( 'Tax total', 'oss', 'woocommerce-germanized' ); + $columns['status'] = _x( 'Status', 'oss', 'woocommerce-germanized' ); + $columns['actions'] = _x( 'Actions', 'oss', 'woocommerce-germanized' ); + + $columns = apply_filters( "{$this->get_hook_prefix()}columns", $columns ); + + return $columns; + } + + /** + * @return array + */ + protected function get_sortable_columns() { + return array( + 'date_start' => array( 'date_start', false ), + 'date_end' => array( 'date_end', false ), + ); + } + + /** + * Gets the name of the default primary column. + * + * @since 4.3.0 + * + * @return string Name of the default primary column, in this case, 'title'. + */ + protected function get_default_primary_column_name() { + return 'title'; + } + + /** + * Handles the default column output. + * + * @since 4.3.0 + * + * @param Report $report The current shipment object. + * @param string $column_name The current column name. + */ + public function column_default( $report, $column_name ) { + do_action( "{$this->get_hook_prefix()}custom_column", $column_name, $report ); + } + + public function get_main_page() { + return 'admin.php?page=oss-reports'; + } + + /** + * Handles actions. + * + * @since 0.0.1 + * + * @param Report $report The current report object. + */ + protected function column_actions( $report ) { + do_action( "{$this->get_hook_prefix()}actions_start", $report ); + + $actions = Admin::get_report_actions( $report ); + + Admin::render_actions( $actions ); + + do_action( "{$this->get_hook_prefix()}actions_end", $report ); + } + + public function column_cb( $report ) { + ?> + + + get_title(); + + echo '' . esc_html( $title ) . ' '; + } + + /** + * @param Report $report + */ + public function column_status( $report ) { + $status = $report->get_status(); + + return '' . esc_html( Package::get_report_status_title( $status ) ) . ''; + } + + /** + * @param Report $report + */ + public function column_net_total( $report ) { + return wc_price( $report->get_net_total() ); + } + + /** + * @param Report $report + */ + public function column_tax_total( $report ) { + return wc_price( $report->get_tax_total() ); + } + + /** + * Handles the post author column output. + * + * @since 4.3.0 + * + * @param Report $report + */ + public function column_date_start( $report ) { + $show_date = $report->get_date_start()->date_i18n( apply_filters( "{$this->get_hook_prefix()}date_format", wc_date_format() ) ); + + printf( + '', + esc_attr( $report->get_date_start()->date( 'c' ) ), + esc_html( $report->get_date_start()->date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) ) ), + esc_html( $show_date ) + ); + } + + /** + * Handles the post author column output. + * + * @since 4.3.0 + * + * @param Report $report + */ + public function column_date_end( $report ) { + $show_date = $report->get_date_end()->date_i18n( apply_filters( "{$this->get_hook_prefix()}date_format", wc_date_format() ) ); + + printf( + '', + esc_attr( $report->get_date_end()->date( 'c' ) ), + esc_html( $report->get_date_end()->date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) ) ), + esc_html( $show_date ) + ); + } + + /** + * + * @param Report $report + */ + public function single_row( $report ) { + $GLOBALS['report'] = $report; + $classes = 'report report-' . $report->get_type(); + ?> + + single_row_columns( $report ); ?> + + get_hook_prefix()}bulk_actions", $actions ); + } +} diff --git a/packages/one-stop-shop-woocommerce/src/Settings.php b/packages/one-stop-shop-woocommerce/src/Settings.php new file mode 100644 index 000000000..f983c39e4 --- /dev/null +++ b/packages/one-stop-shop-woocommerce/src/Settings.php @@ -0,0 +1,203 @@ + _x( 'General', 'oss', 'woocommerce-germanized' ), + ); + } + + public static function get_description() { + return sprintf( _x( 'Find useful options regarding the One Stop Shop procedure here.', 'oss', 'woocommerce-germanized' ) ); + } + + public static function get_help_url() { + return 'https://vendidero.github.io/one-stop-shop-woocommerce/'; + } + + public static function get_settings( $current_section = '' ) { + $settings = array( + array( + 'title' => '', + 'type' => 'title', + 'id' => 'oss_options', + 'desc' => Package::is_integration() ? '' : self::get_description(), + ), + + array( + 'title' => _x( 'OSS status', 'oss', 'woocommerce-germanized' ), + 'desc' => _x( 'Yes, I\'m currently participating in the OSS procedure.', 'oss', 'woocommerce-germanized' ), + 'id' => 'oss_use_oss_procedure', + 'type' => Package::is_integration() ? 'gzd_toggle' : 'checkbox', + 'default' => 'no', + ), + + array( + 'title' => _x( 'Observation', 'oss', 'woocommerce-germanized' ), + 'desc' => _x( 'Automatically observe the delivery threshold of the current year.', 'oss', 'woocommerce-germanized' ) . '

' . _x( 'This option will automatically calculate the amount applicable for the OSS procedure delivery threshold once per day for the current year. The report will only recalculated for the days which are not yet subject to the observation to save processing time.', 'oss', 'woocommerce-germanized' ) . '

', + 'id' => 'oss_enable_auto_observation', + 'type' => Package::is_integration() ? 'gzd_toggle' : 'checkbox', + 'default' => 'yes', + ), + ); + + if ( Package::enable_auto_observer() ) { + $settings = array_merge( + $settings, + array( + array( + 'title' => sprintf( _x( 'Delivery threshold', 'oss', 'woocommerce-germanized' ) ), + 'id' => 'oss_delivery_threshold', + 'type' => 'html', + 'html' => self::get_observer_report_html(), + ), + ) + ); + } + + $settings = array_merge( + $settings, + array( + array( + 'title' => _x( 'Participation', 'oss', 'woocommerce-germanized' ), + 'id' => 'oss_switch', + 'type' => 'html', + 'html' => self::get_oss_switch_html(), + ), + + array( + 'title' => _x( 'Report Order Date', 'oss', 'woocommerce-germanized' ), + 'desc' => '

' . _x( 'Select the relevant order date to be used to determine whether to include an order in a report.', 'oss', 'woocommerce-germanized' ) . '

', + 'id' => 'oss_report_date_type', + 'type' => 'select', + 'default' => 'date_paid', + 'options' => array( + 'date_paid' => _x( 'Date paid', 'oss', 'woocommerce-germanized' ), + 'date_created' => _x( 'Date created', 'oss', 'woocommerce-germanized' ), + ), + ), + ) + ); + + if ( Helper::oss_procedure_is_enabled() && wc_prices_include_tax() ) { + $settings = array_merge( + $settings, + array( + array( + 'title' => _x( 'Fixed gross prices', 'oss', 'woocommerce-germanized' ), + 'desc' => _x( 'Apply the same gross price regardless of the tax rate for EU countries.', 'oss', 'woocommerce-germanized' ) . '

' . _x( 'This option will make sure that your customers pay the same price no matter the tax rate (based on the country chosen) to be applied.', 'oss', 'woocommerce-germanized' ) . '

', + 'id' => 'oss_fixed_gross_prices', + 'type' => Package::is_integration() ? 'gzd_toggle' : 'checkbox', + 'default' => 'yes', + ), + array( + 'title' => _x( 'Third countries', 'oss', 'woocommerce-germanized' ), + 'desc' => _x( 'Apply the same gross price for third countries too.', 'oss', 'woocommerce-germanized' ), + 'id' => 'oss_fixed_gross_prices_for_third_countries', + 'type' => Package::is_integration() ? 'gzd_toggle' : 'checkbox', + 'default' => 'no', + 'custom_attributes' => array( + 'data-show_if_oss_fixed_gross_prices' => '', + ), + ), + ) + ); + } + + $settings = array_merge( + $settings, + array( + array( + 'type' => 'sectionend', + 'id' => 'oss_options', + ), + ) + ); + + return $settings; + } + + public static function get_oss_switch_link() { + return add_query_arg( array( 'action' => 'oss_switch_procedure' ), wp_nonce_url( admin_url( 'admin-post.php' ), 'oss_switch_procedure' ) ); + } + + protected static function get_oss_switch_html() { + ob_start(); + ?> +

+ + + +

+

+ get_url() ) . '">' . esc_html_x( 'See status', 'oss', 'woocommerce-germanized' ) . '' : '' . esc_html_x( 'Start initial report', 'oss', 'woocommerce-germanized' ) . ''; + $status_text = sprintf( ( $running ? esc_html_x( 'Report not yet completed. %s', 'oss', 'woocommerce-germanized' ) : esc_html_x( 'Report not yet started. %s', 'oss', 'woocommerce-germanized' ) ), $status_link ); + ob_start(); + ?> +

+ get_net_total() >= Package::get_delivery_threshold() ) { + $total_class = 'observer-total-red'; + } elseif ( $observer_report->get_net_total() >= Package::get_delivery_notification_threshold() ) { + $total_class = 'observer-total-orange'; + } + + ob_start(); + ?> +

get_net_total() ); ?> get_date_end() ) ); ?>

+

Find out more about the calculation.', 'oss', 'woocommerce-germanized' ), 'https://vendidero.github.io/one-stop-shop-woocommerce/report-calculation' ) ); ?>

+ id = 'oss'; + $this->label = _x( 'OSS', 'oss', 'woocommerce-germanized' ); + + parent::__construct(); + } + + public function output() { + echo '

' . esc_html_x( 'One Stop Shop', 'oss', 'woocommerce-germanized' ) . ' ' . esc_html_x( 'Reports', 'oss', 'woocommerce-germanized' ) . ' ' . esc_html_x( 'Learn More', 'oss', 'woocommerce-germanized' ) . '

'; + + parent::output(); + } + + /** + * Get sections. + * + * @return array + */ + public function get_sections() { + $sections = Settings::get_sections(); + + return apply_filters( 'woocommerce_get_sections_' . $this->id, $sections ); + } + + public function save() { + Settings::before_save(); + parent::save(); + Settings::after_save(); + } + + /** + * Get settings array. + * + * @return array + */ + public function get_settings( $current_section = '' ) { + $settings = Settings::get_settings( $current_section ); + + return apply_filters( 'woocommerce_get_settings_' . $this->id, $settings ); + } + + public function get_settings_for_section_core( $section_id ) { + return Settings::get_settings( $section_id ); + } +} diff --git a/packages/one-stop-shop-woocommerce/src/Tax.php b/packages/one-stop-shop-woocommerce/src/Tax.php new file mode 100644 index 000000000..f58f792c0 --- /dev/null +++ b/packages/one-stop-shop-woocommerce/src/Tax.php @@ -0,0 +1,528 @@ +needs_shipping() ) { + return true; + } + + return false; + } + + protected static function filter_cart_items_calculated_totals( $item ) { + return isset( $item['line_total'] ); + } + + /** + * As prices may change based on the customers address and VAT status (e.g. exempt) + * it is necessary to make sure that shipping tax is recalculated too in case shipping costs include taxes. + */ + public static function invalidate_shipping_session( $cart ) { + if ( apply_filters( 'oss_shipping_costs_include_taxes', false ) ) { + if ( $cart ) { + $items = array_values( array_filter( $cart->get_cart(), array( __CLASS__, 'filter_cart_items_available_for_shipping' ) ) ); + $items_calculated = array_values( array_filter( $items, array( __CLASS__, 'filter_cart_items_calculated_totals' ) ) ); + + /** + * Make sure totals have already been calculated (for all items) to prevent missing array key warnings + * while calling WC_Cart::get_shipping_packages() + */ + if ( count( $items ) > 0 && $items == $items_calculated ) { // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison + foreach ( $cart->get_shipping_packages() as $package_key => $package ) { + $session_key = "shipping_for_package_{$package_key}"; + + unset( WC()->session->$session_key ); + } + } + } + } + } + + /** + * In case the order/customer is a VAT exempt, use the base address as tax location. + * + * @param $location + * + * @return array|mixed + */ + public static function vat_exempt_taxable_address( $location ) { + if ( Helper::current_request_has_vat_exempt() ) { + $location = array( + WC()->countries->get_base_country(), + WC()->countries->get_base_state(), + WC()->countries->get_base_postcode(), + WC()->countries->get_base_city(), + ); + } + + return $location; + } + + /** + * @param $tax_class + * @param \WC_Product $product + */ + public static function filter_tax_class( $tax_class, $product ) { + $taxable_address = Helper::get_taxable_location(); + + if ( isset( $taxable_address[0] ) && ! empty( $taxable_address[0] ) && WC()->countries->get_base_country() !== $taxable_address[0] ) { + + $address = array( + 'country' => $taxable_address[0], + 'state' => isset( $taxable_address[1] ) ? $taxable_address[1] : '', + 'postcode' => isset( $taxable_address[2] ) ? $taxable_address[2] : '', + 'city' => isset( $taxable_address[3] ) ? $taxable_address[3] : '', + ); + + $tax_class = self::get_product_tax_class_by_country( $product, $address, $tax_class ); + } + + return $tax_class; + } + + /** + * @param \WC_Product_Variation $variation + * @param $i + */ + public static function save_variation_options( $variation, $i ) { + $parent = wc_get_product( $variation->get_parent_id() ); + $tax_classes = self::get_product_tax_classes( $variation, $parent, 'edit' ); + $parent_tax_classes = self::get_product_tax_classes( $parent ); + $product_tax_class = $variation->get_tax_class(); + + $posted = isset( $_POST['variable_tax_class_by_countries'][ $i ] ) ? wc_clean( (array) wp_unslash( $_POST['variable_tax_class_by_countries'][ $i ] ) ) : array(); // phpcs:ignore WordPress.Security.NonceVerification.Missing + $new_classes = isset( $_POST['variable_tax_class_by_countries_new_tax_class'][ $i ] ) ? wc_clean( (array) wp_unslash( $_POST['variable_tax_class_by_countries_new_tax_class'][ $i ] ) ) : array(); // phpcs:ignore WordPress.Security.NonceVerification.Missing + $new_countries = isset( $_POST['variable_tax_class_by_countries_new_countries'][ $i ] ) ? wc_clean( (array) wp_unslash( $_POST['variable_tax_class_by_countries_new_countries'][ $i ] ) ) : array(); // phpcs:ignore WordPress.Security.NonceVerification.Missing + + foreach ( $tax_classes as $country => $tax_class ) { + // Maybe delete missing tax classes (e.g. removed by the user) + if ( ! isset( $posted[ $country ] ) || 'parent' === $posted[ $country ] ) { + unset( $tax_classes[ $country ] ); + } else { + $tax_classes[ $country ] = $posted[ $country ]; + } + } + + foreach ( $new_countries as $key => $country ) { + if ( empty( $country ) ) { + continue; + } + + if ( ! array_key_exists( $country, $tax_classes ) && isset( $new_classes[ $key ] ) && 'parent' !== $new_classes[ $key ] ) { + $tax_classes[ $country ] = $new_classes[ $key ]; + } + } + + /** + * Remove tax classes which match the products main tax class or the base country + */ + foreach ( $tax_classes as $country => $tax_class ) { + if ( $tax_class === $product_tax_class || WC()->countries->get_base_country() === $country ) { + unset( $tax_classes[ $country ] ); + } elseif ( isset( $parent_tax_classes[ $country ] ) && $parent_tax_classes[ $country ] === $tax_class ) { + unset( $tax_classes[ $country ] ); + } elseif ( 'parent' === $tax_class ) { + unset( $tax_classes[ $country ] ); + } + } + + if ( empty( $tax_classes ) ) { + $variation->delete_meta_data( '_tax_class_by_countries' ); + } else { + $variation->update_meta_data( '_tax_class_by_countries', $tax_classes ); + } + } + + /** + * @param \WC_Product $product + */ + public static function save_product_options( $product ) { + $tax_classes = self::get_product_tax_classes( $product ); + $product_tax_class = $product->get_tax_class(); + + $posted = isset( $_POST['_tax_class_by_countries'] ) ? wc_clean( (array) wp_unslash( $_POST['_tax_class_by_countries'] ) ) : array(); // phpcs:ignore WordPress.Security.NonceVerification.Missing + $new_classes = isset( $_POST['_tax_class_by_countries_new_tax_class'] ) ? wc_clean( (array) wp_unslash( $_POST['_tax_class_by_countries_new_tax_class'] ) ) : array(); // phpcs:ignore WordPress.Security.NonceVerification.Missing + $new_countries = isset( $_POST['_tax_class_by_countries_new_countries'] ) ? wc_clean( (array) wp_unslash( $_POST['_tax_class_by_countries_new_countries'] ) ) : array(); // phpcs:ignore WordPress.Security.NonceVerification.Missing + + foreach ( $tax_classes as $country => $tax_class ) { + // Maybe delete missing tax classes (e.g. removed by the user) + if ( ! isset( $posted[ $country ] ) ) { + unset( $tax_classes[ $country ] ); + } else { + $tax_classes[ $country ] = $posted[ $country ]; + } + } + + foreach ( $new_countries as $key => $country ) { + if ( empty( $country ) ) { + continue; + } + + if ( ! array_key_exists( $country, $tax_classes ) && isset( $new_classes[ $key ] ) ) { + $tax_classes[ $country ] = $new_classes[ $key ]; + } + } + + /** + * Remove tax classes which match the products main tax class or the base country + */ + foreach ( $tax_classes as $country => $tax_class ) { + if ( $tax_class === $product_tax_class || WC()->countries->get_base_country() === $country ) { + unset( $tax_classes[ $country ] ); + } + } + + if ( empty( $tax_classes ) ) { + $product->delete_meta_data( '_tax_class_by_countries' ); + } else { + $product->update_meta_data( '_tax_class_by_countries', $tax_classes ); + } + } + + /** + * @param $loop + * @param $variation_data + * @param \WP_Post $variation + */ + public static function variation_tax_product_options( $loop, $variation_data, $variation ) { + global $product_object; + + if ( ! $variation = wc_get_product( $variation ) ) { + return; + } + + $tax_classes = self::get_product_tax_classes( $variation, $product_object, 'edit' ); + $countries_left = self::get_selectable_countries(); + + if ( ! empty( $tax_classes ) ) { + foreach ( $tax_classes as $country => $tax_class ) { + $countries_left = array_diff_key( $countries_left, array( $country => '' ) ); + + woocommerce_wp_select( + array( + 'id' => "variable_tax_class_by_countries{$loop}_{$country}", + 'name' => "variable_tax_class_by_countries[{$loop}][{$country}]", + 'value' => $tax_class, + 'label' => sprintf( _x( 'Tax class (%s)', 'oss', 'woocommerce-germanized' ), $country ), + 'options' => array( 'parent' => _x( 'Same as parent', 'oss', 'woocommerce-germanized' ) ) + wc_get_product_tax_class_options(), + 'wrapper_class' => 'oss-tax-class-by-country-field form-row form-row-full', + 'description' => '' . _x( 'remove', 'oss', 'woocommerce-germanized' ) . '', + ) + ); + } + } + ?> +
+ +

+ + + +

+ +
+

+ + + + + +

+
+ _x( 'EU-wide', 'oss', 'woocommerce-germanized' ) ); + + return $eu + $countries; + } + + protected static function get_country_name( $country_code ) { + $country_name = $country_code; + $countries = WC()->countries ? WC()->countries->get_countries() : array(); + + if ( 'EU-wide' === $country_code ) { + $country_name = _x( 'EU-wide', 'oss', 'woocommerce-germanized' ); + } elseif ( isset( $countries[ $country_code ] ) ) { + $country_name = $countries[ $country_code ]; + } + + return $country_name; + } + + public static function tax_product_options() { + global $product_object; + + $tax_classes = self::get_product_tax_classes( $product_object ); + $countries_left = self::get_selectable_countries(); + + if ( ! empty( $tax_classes ) ) { + foreach ( $tax_classes as $country => $tax_class ) { + $countries_left = array_diff_key( $countries_left, array( $country => '' ) ); + + woocommerce_wp_select( + array( + 'id' => '_tax_class_by_countries_' . $country, + 'name' => '_tax_class_by_countries[' . $country . ']', + 'value' => $tax_class, + 'label' => sprintf( _x( 'Tax class (%s)', 'oss', 'woocommerce-germanized' ), $country ), + 'options' => wc_get_product_tax_class_options(), + 'description' => '' . _x( 'remove', 'oss', 'woocommerce-germanized' ) . '', + ) + ); + } + } + + ?> +
+ +

+ + + +

+ +
+

+ + + + + +

+
+ '', + 'state' => '', + 'postcode' => '', + 'city' => '', + ) + ); + + $tax_class = false !== $default ? $default : $product->get_tax_class(); + $postcode = wc_normalize_postcode( $address['postcode'] ); + $filter_tax_class = true; + + /** + * Prevent tax class adjustment for GB (except Norther Ireland via postcode detection) + */ + if ( 'GB' === $address['country'] && ( empty( $postcode ) || 'BT' !== substr( $postcode, 0, 2 ) ) ) { + $filter_tax_class = false; + } + + if ( apply_filters( 'oss_woocommerce_switch_product_tax_class', $filter_tax_class, $product, $address['country'], $postcode, $default ) ) { + $cache_suffix = '_oss_tax_class_' . md5( sprintf( '%s+%s+%s+%s+%s', $address['country'], $address['state'], $address['city'], $postcode, $product->get_id() ) ); + $cache_key = \WC_Cache_Helper::get_cache_prefix( 'product_' . $product->get_id() ) . $cache_suffix; + $cache_key_tax = \WC_Cache_Helper::get_cache_prefix( 'taxes' ) . $cache_suffix; + $matched_tax_cache = wp_cache_get( $cache_key_tax, 'taxes' ); + $matched_tax_class = false !== $matched_tax_cache ? wp_cache_get( $cache_key, 'products' ) : false; + + if ( false === $matched_tax_class ) { + $tax_classes = self::get_product_tax_classes( $product ); + $tax_class_slugs = Helper::get_tax_class_slugs(); + + if ( array_key_exists( $address['country'], $tax_classes ) ) { + $tax_class = $tax_classes[ $address['country'] ]; + } elseif ( isset( $tax_classes['EU-wide'] ) ) { + $tax_class = $tax_classes['EU-wide']; + } + + if ( $tax_class_slugs['super-reduced'] === $tax_class ) { + $tax_rates = \WC_Tax::find_rates( + array( + 'country' => $address['country'], + 'state' => $address['state'], + 'city' => $address['city'], + 'postcode' => $postcode, + 'tax_class' => $tax_class, + ) + ); + + /** + * Country does not seem to support this tax class - fallback to the reduced tax class + */ + if ( empty( $tax_rates ) ) { + $tax_class = $tax_class_slugs['reduced']; + } + } + + if ( $tax_class_slugs['greater-reduced'] === $tax_class ) { + $tax_rates = \WC_Tax::find_rates( + array( + 'country' => $address['country'], + 'state' => $address['state'], + 'city' => $address['city'], + 'postcode' => $postcode, + 'tax_class' => $tax_class, + ) + ); + + /** + * Country does not seem to support this tax class - fallback to the reduced tax class + */ + if ( empty( $tax_rates ) ) { + $tax_class = $tax_class_slugs['reduced']; + } + } + + if ( $tax_class_slugs['reduced'] === $tax_class ) { + $tax_rates = \WC_Tax::find_rates( + array( + 'country' => $address['country'], + 'state' => $address['state'], + 'city' => $address['city'], + 'postcode' => $postcode, + 'tax_class' => $tax_class, + ) + ); + + /** + * Country does not seem to support this tax class - fallback to the standard tax class + */ + if ( empty( $tax_rates ) ) { + $tax_class = $tax_class_slugs['standard']; + } + } + + /** + * This cache entry depends on both the tax and product data. + */ + wp_cache_set( $cache_key_tax, $cache_key, 'taxes' ); + wp_cache_set( $cache_key, $tax_class, 'products' ); + } else { + $tax_class = $matched_tax_class; + } + } + + return $tax_class; + } + + /** + * @param \WC_Product $product + */ + public static function get_product_tax_classes( $product, $parent = false, $context = 'view' ) { + $tax_classes = $product->get_meta( '_tax_class_by_countries', true ); + $tax_classes = ( ! is_array( $tax_classes ) || empty( $tax_classes ) ) ? array() : $tax_classes; + + /** + * Merge with parent tax classes + */ + if ( is_a( $product, 'WC_Product_Variation' ) ) { + $parent = $parent ? $parent : wc_get_product( $product->get_parent_id() ); + + if ( $parent ) { + $parent_tax_classes = self::get_product_tax_classes( $parent ); + $tax_classes = array_replace_recursive( $parent_tax_classes, $tax_classes ); + + foreach ( $tax_classes as $country => $tax_class ) { + $parent_tax_class = isset( $parent_tax_classes[ $country ] ) ? $parent_tax_classes[ $country ] : false; + + if ( 'view' === $context && 'parent' === $tax_class ) { + if ( $parent_tax_class ) { + $tax_classes[ $country ] = $parent_tax_class; + } else { + unset( $tax_classes[ $country ] ); + } + } elseif ( 'edit' === $context && $tax_class === $parent_tax_class ) { + $tax_classes[ $country ] = 'parent'; + } + } + } + } + + return $tax_classes; + } +} diff --git a/packages/one-stop-shop-woocommerce/templates/emails/admin-delivery-threshold.php b/packages/one-stop-shop-woocommerce/templates/emails/admin-delivery-threshold.php new file mode 100644 index 000000000..720456f47 --- /dev/null +++ b/packages/one-stop-shop-woocommerce/templates/emails/admin-delivery-threshold.php @@ -0,0 +1,42 @@ + + + +

OSS Settings Panel for details.', 'oss', 'woocommerce-germanized' ), wc_price( \Vendidero\OneStopShop\Package::get_delivery_notification_threshold() ), esc_url( \Vendidero\OneStopShop\Settings::get_settings_url() ) ) ); ?>

+ +

+ +
    +
  • : get_date_start()->format( wc_date_format() ) ); ?> - get_date_end()->format( wc_date_format() ) ); ?>
  • +
  • : get_net_total() ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
  • +
  • : get_tax_total() ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
  • +
+ + +get_url() ); + +/** + * Show user-defined additional content - this is set in each email's settings. + */ +if ( $additional_content ) { + echo esc_html( wp_strip_all_tags( wptexturize( $additional_content ) ) ); + echo "\n\n----------------------------------------\n\n"; +} + +echo "\n----------------------------------------\n\n"; + +echo wp_kses_post( apply_filters( 'woocommerce_email_footer_text', get_option( 'woocommerce_email_footer_text' ) ) ); diff --git a/packages/one-stop-shop-woocommerce/wpml-config.xml b/packages/one-stop-shop-woocommerce/wpml-config.xml new file mode 100644 index 000000000..6de03ace2 --- /dev/null +++ b/packages/one-stop-shop-woocommerce/wpml-config.xml @@ -0,0 +1,5 @@ + + + _tax_class_by_countries + + \ No newline at end of file diff --git a/packages/woocommerce-eu-tax-helper/src/Helper.php b/packages/woocommerce-eu-tax-helper/src/Helper.php new file mode 100644 index 000000000..bc9d680ba --- /dev/null +++ b/packages/woocommerce-eu-tax-helper/src/Helper.php @@ -0,0 +1,911 @@ +countries->get_european_union_countries(); + + return $countries; + } + + public static function get_eu_vat_countries() { + return apply_filters( 'woocommerce_eu_tax_helper_eu_vat_countries', WC()->countries->get_european_union_countries( 'eu_vat' ) ); + } + + public static function is_northern_ireland( $country, $postcode = '' ) { + if ( 'GB' === $country && 'BT' === strtoupper( substr( trim( $postcode ), 0, 2 ) ) ) { + return true; + } elseif ( 'IX' === $country ) { + return true; + } + + return false; + } + + public static function is_eu_vat_country( $country, $postcode = '' ) { + $country = wc_strtoupper( $country ); + $postcode = wc_normalize_postcode( $postcode ); + $is_eu_vat_country = in_array( $country, self::get_eu_vat_countries(), true ); + + if ( self::is_northern_ireland( $country, $postcode ) ) { + $is_eu_vat_country = true; + } elseif ( self::is_eu_vat_postcode_exemption( $country, $postcode ) ) { + $is_eu_vat_country = false; + } + + return apply_filters( 'woocommerce_eu_tax_helper_is_eu_vat_country', $is_eu_vat_country, $country, $postcode ); + } + + public static function is_third_country( $country, $postcode = '' ) { + $is_third_country = true; + + /** + * In case the base country is within EU consider all non-EU VAT countries as third countries. + * In any other case consider every non-base-country as third country. + */ + if ( in_array( self::get_base_country(), self::get_eu_vat_countries(), true ) ) { + $is_third_country = ! self::is_eu_vat_country( $country, $postcode ); + } else { + $is_third_country = self::get_base_country() !== $country; + } + + return apply_filters( 'woocommerce_eu_tax_helper_is_third_country', $is_third_country, $country, $postcode ); + } + + public static function is_eu_country( $country ) { + return in_array( $country, self::get_eu_countries(), true ); + } + + public static function is_eu_vat_postcode_exemption( $country, $postcode = '' ) { + $country = wc_strtoupper( $country ); + $postcode = wc_normalize_postcode( $postcode ); + $exemptions = self::get_vat_postcode_exemptions_by_country(); + $is_exempt = false; + + if ( ! empty( $postcode ) && in_array( $country, self::get_eu_vat_countries(), true ) ) { + if ( array_key_exists( $country, $exemptions ) ) { + $wildcards = wc_get_wildcard_postcodes( $postcode, $country ); + + foreach ( $exemptions[ $country ] as $exempt_postcode ) { + if ( in_array( $exempt_postcode, $wildcards, true ) ) { + $is_exempt = true; + break; + } + } + } + } + + return $is_exempt; + } + + /** + * Get VAT exemptions (of EU countries) for certain postcodes (e.g. canary islands) + * + * @see https://www.hk24.de/produktmarken/beratung-service/recht-und-steuern/steuerrecht/umsatzsteuer-mehrwertsteuer/umsatzsteuer-mehrwertsteuer-international/verfahrensrecht/territoriale-besonderheiten-umsatzsteuer-zollrecht-1167674 + * @see https://github.com/woocommerce/woocommerce/issues/5143 + * @see https://ec.europa.eu/taxation_customs/business/vat/eu-vat-rules-topic/territorial-status-eu-countries-certain-territories_en + * + * @return \string[][] + */ + public static function get_vat_postcode_exemptions_by_country( $country = '' ) { + $country = wc_strtoupper( $country ); + + $exemptions = array( + 'DE' => array( + '27498', // Helgoland + '78266', // Büsingen am Hochrhein + ), + 'ES' => array( + '35*', // Canary Islands + '38*', // Canary Islands + '51*', // Ceuta + '52*', // Melilla + ), + 'GR' => array( + '63086', // Mount Athos + '63087', // Mount Athos + ), + 'FR' => array( + '971*', // Guadeloupe + '972*', // Martinique + '973*', // French Guiana + '974*', // Réunion + '976*', // Mayotte + ), + 'IT' => array( + '22060', // Livigno, Campione d’Italia + '23030', // Lake Lugano + ), + 'FI' => array( + '22*', // Aland islands + ), + ); + + if ( empty( $country ) ) { + return $exemptions; + } elseif ( array_key_exists( $country, $exemptions ) ) { + return $exemptions[ $country ]; + } else { + return array(); + } + } + + /** + * @param integer|\WC_Order $order + * + * @return array + */ + public static function get_order_taxable_location( $order ) { + $order = is_a( $order, 'WC_Order' ) ? $order : wc_get_order( $order ); + + $taxable_address = array( + WC()->countries->get_base_country(), + WC()->countries->get_base_state(), + WC()->countries->get_base_postcode(), + WC()->countries->get_base_city(), + ); + + if ( ! $order ) { + return $taxable_address; + } + + $tax_based_on = get_option( 'woocommerce_tax_based_on' ); + + if ( is_a( $order, 'WC_Order_Refund' ) ) { + $order = wc_get_order( $order->get_parent_id() ); + + if ( ! $order ) { + return $taxable_address; + } + } + + /** + * Shipping address data does not exist + */ + if ( 'shipping' === $tax_based_on && ! $order->get_shipping_country() ) { + $tax_based_on = 'billing'; + } + + $is_vat_exempt = apply_filters( 'woocommerce_order_is_vat_exempt', 'yes' === $order->get_meta( 'is_vat_exempt' ), $order ); + + /** + * In case the order is a VAT exempt, calculate net prices based on taxes from base country. + */ + if ( $is_vat_exempt ) { + $tax_based_on = 'base'; + } + + $country = 'shipping' === $tax_based_on ? $order->get_shipping_country() : $order->get_billing_country(); + + if ( 'base' !== $tax_based_on && ! empty( $country ) ) { + $taxable_address = array( + $country, + 'billing' === $tax_based_on ? $order->get_billing_state() : $order->get_shipping_state(), + 'billing' === $tax_based_on ? $order->get_billing_postcode() : $order->get_shipping_postcode(), + 'billing' === $tax_based_on ? $order->get_billing_city() : $order->get_shipping_city(), + ); + } + + return $taxable_address; + } + + public static function get_taxable_location() { + $is_admin_order_request = self::is_admin_order_request(); + + if ( $is_admin_order_request ) { + $taxable_address = array( + WC()->countries->get_base_country(), + WC()->countries->get_base_state(), + WC()->countries->get_base_postcode(), + WC()->countries->get_base_city(), + ); + + if ( isset( $_POST['order_id'] ) && ( $order = wc_get_order( absint( $_POST['order_id'] ) ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing + $taxable_address = self::get_order_taxable_location( $order ); + } + + return $taxable_address; + } else { + return \WC_Tax::get_tax_location(); + } + } + + public static function is_admin_order_ajax_request() { + $order_actions = array( 'woocommerce_calc_line_taxes', 'woocommerce_save_order_items', 'add_coupon_discount', 'refund_line_items', 'delete_refund' ); + + return isset( $_POST['action'], $_POST['order_id'] ) && ( strstr( wc_clean( wp_unslash( $_POST['action'] ) ), '_order_' ) || in_array( wc_clean( wp_unslash( $_POST['action'] ) ), $order_actions, true ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing + } + + public static function is_admin_order_request() { + return is_admin() && current_user_can( 'edit_shop_orders' ) && self::is_admin_order_ajax_request(); + } + + public static function current_request_has_vat_exempt() { + $is_admin_order_request = self::is_admin_order_request(); + $is_vat_exempt = false; + + if ( $is_admin_order_request ) { + if ( $order = wc_get_order( absint( $_POST['order_id'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.ValidatedSanitizedInput.InputNotValidated + $is_vat_exempt = apply_filters( 'woocommerce_order_is_vat_exempt', 'yes' === $order->get_meta( 'is_vat_exempt' ), $order ); + } + } else { + if ( WC()->customer && WC()->customer->is_vat_exempt() ) { + $is_vat_exempt = true; + } + } + + return $is_vat_exempt; + } + + public static function get_base_country() { + if ( WC()->countries ) { + return WC()->countries->get_base_country(); + } else { + return wc_get_base_location()['country']; + } + } + + /** + * Returns a list of EU countries except base country. + * + * @return string[] + */ + public static function get_non_base_eu_countries( $include_gb = false ) { + $countries = WC()->countries->get_european_union_countries( 'eu_vat' ); + + /** + * Include GB to allow Northern Ireland + */ + if ( $include_gb && ! in_array( 'GB', $countries, true ) ) { + $countries = array_merge( $countries, array( 'GB' ) ); + } + + $base_country = self::get_base_country(); + $countries = array_diff( $countries, array( $base_country ) ); + + return $countries; + } + + public static function country_supports_eu_vat( $country, $postcode = '' ) { + return self::is_eu_vat_country( $country, $postcode ); + } + + public static function import_oss_tax_rates( $tax_class_slug_names = array() ) { + self::import_tax_rates_internal( true, $tax_class_slug_names ); + } + + public static function import_default_tax_rates( $tax_class_slug_names = array() ) { + self::import_tax_rates_internal( false, $tax_class_slug_names ); + } + + public static function import_tax_rates( $tax_class_slug_names = array() ) { + self::import_tax_rates_internal( self::oss_procedure_is_enabled(), $tax_class_slug_names ); + } + + protected static function parse_tax_class_slug_names( $tax_class_slug_names = array() ) { + return wp_parse_args( + $tax_class_slug_names, + array( + 'reduced' => apply_filters( 'woocommerce_eu_tax_helper_tax_class_reduced_name', __( 'Reduced rate', 'woocommerce' ) ), // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch + 'greater-reduced' => apply_filters( 'woocommerce_eu_tax_helper_tax_class_greater_reduced_name', _x( 'Greater reduced rate', 'tax-helper-tax-class-name', 'woocommerce-germanized' ) ), + 'super-reduced' => apply_filters( 'woocommerce_eu_tax_helper_tax_class_super_reduced_name', _x( 'Super reduced rate', 'tax-helper-tax-class-name', 'woocommerce-germanized' ) ), + ) + ); + } + + protected static function import_tax_rates_internal( $is_oss = true, $tax_class_slug_names = array() ) { + self::clear_cache(); + + $tax_class_slugs = self::get_tax_class_slugs( $tax_class_slug_names ); + $tax_class_slug_names = self::parse_tax_class_slug_names( $tax_class_slug_names ); + $eu_rates = self::get_eu_tax_rates(); + + foreach ( $tax_class_slugs as $tax_class_type => $class ) { + /** + * Maybe create missing tax classes + */ + if ( false === $class ) { + switch ( $tax_class_type ) { + case 'reduced': + /* translators: Do not translate */ + \WC_Tax::create_tax_class( $tax_class_slug_names['reduced'] ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch + break; + case 'greater-reduced': + \WC_Tax::create_tax_class( $tax_class_slug_names['greater-reduced'] ); + break; + case 'super-reduced': + \WC_Tax::create_tax_class( $tax_class_slug_names['super-reduced'] ); + break; + } + } + + $new_rates = array(); + + foreach ( $eu_rates as $country => $rates_data ) { + + /** + * Use base country rates in case OSS is disabled + */ + if ( ! $is_oss ) { + $base_country = self::get_base_country(); + + if ( isset( $eu_rates[ $base_country ] ) ) { + /** + * In case the country includes multiple rules (e.g. postcode exempts) by default + * do only use the last rule (which does not include exempts) to construct non-base country tax rules. + */ + if ( $base_country !== $country ) { + $base_country_base_rate = array_values( array_slice( $eu_rates[ $base_country ], -1 ) )[0]; + + foreach ( $rates_data as $key => $rate_data ) { + $rates_data[ $key ] = array_replace_recursive( $rate_data, $base_country_base_rate ); + + foreach ( $tax_class_slugs as $tmp_class_type => $class_data ) { + /** + * Do not include tax classes which are not supported by the base country. + */ + if ( isset( $rates_data[ $key ][ $tmp_class_type ] ) && ! isset( $base_country_base_rate[ $tmp_class_type ] ) ) { + unset( $rates_data[ $key ][ $tmp_class_type ] ); + } elseif ( isset( $rates_data[ $key ][ $tmp_class_type ] ) ) { + /** + * Replace tax class data with base data to make sure that reduced + * classes have the same dimensions + */ + $rates_data[ $key ][ $tmp_class_type ] = $base_country_base_rate[ $tmp_class_type ]; + + /** + * In case this is an exempt make sure to replace with zero tax rates + */ + if ( isset( $rate_data['is_exempt'] ) && $rate_data['is_exempt'] ) { + if ( is_array( $rates_data[ $key ][ $tmp_class_type ] ) ) { + foreach ( $rates_data[ $key ][ $tmp_class_type ] as $k => $rate ) { + $rates_data[ $key ][ $tmp_class_type ][ $k ] = 0; + } + } else { + $rates_data[ $key ][ $tmp_class_type ] = 0; + } + } + } + } + } + } + } else { + continue; + } + } + + /** + * Each country may contain multiple tax rates + */ + foreach ( $rates_data as $rates ) { + + $rates = wp_parse_args( + $rates, + array( + 'name' => '', + 'postcodes' => array(), + 'reduced' => array(), + ) + ); + + if ( ! empty( $rates['postcode'] ) ) { + foreach ( $rates['postcode'] as $postcode ) { + $tax_rate = self::get_single_tax_rate_data( $tax_class_type, $rates, $country, $postcode ); + + if ( false !== $tax_rate ) { + $new_rates[] = $tax_rate; + } + } + } else { + $tax_rate = self::get_single_tax_rate_data( $tax_class_type, $rates, $country ); + + if ( false !== $tax_rate ) { + $new_rates[] = $tax_rate; + } + } + } + } + + self::import_rates( $new_rates, $class ); + } + } + + private static function get_single_tax_rate_data( $tax_class_type, $rates, $country, $postcode = '' ) { + $rates = wp_parse_args( + $rates, + array( + 'name' => '', + 'reduced' => array(), + ) + ); + + $single_rate = array( + 'name' => $rates['name'], + 'rate' => false, + 'country' => $country, + 'postcode' => $postcode, + ); + + switch ( $tax_class_type ) { + case 'greater-reduced': + if ( count( $rates['reduced'] ) > 1 ) { + $single_rate['rate'] = $rates['reduced'][1]; + } + break; + case 'reduced': + if ( ! empty( $rates['reduced'] ) ) { + $single_rate['rate'] = $rates['reduced'][0]; + } + break; + default: + if ( isset( $rates[ $tax_class_type ] ) ) { + $single_rate['rate'] = $rates[ $tax_class_type ]; + } + break; + } + + if ( false === $single_rate['rate'] ) { + return false; + } + + return $single_rate; + } + + protected static function clear_cache() { + $cache_key = \WC_Cache_Helper::get_cache_prefix( 'taxes' ) . 'eu_tax_helper_tax_class_slugs'; + + wp_cache_delete( $cache_key, 'taxes' ); + } + + public static function get_tax_class_slugs( $tax_class_slug_names = array() ) { + $tax_class_slug_names = self::parse_tax_class_slug_names( $tax_class_slug_names ); + $cache_key = \WC_Cache_Helper::get_cache_prefix( 'taxes' ) . 'eu_tax_helper_tax_class_slugs'; + $slugs = wp_cache_get( $cache_key, 'taxes' ); + + if ( false === $slugs ) { + $reduced_tax_class = false; + $greater_reduced_tax_class = false; + $super_reduced_tax_class = false; + $tax_classes = \WC_Tax::get_tax_class_slugs(); + + /** + * Try to determine the reduced tax rate class + */ + foreach ( $tax_classes as $slug ) { + if ( strstr( $slug, 'virtual' ) ) { + continue; + } + + if ( ! $greater_reduced_tax_class && strstr( $slug, sanitize_title( 'Greater reduced rate' ) ) ) { + $greater_reduced_tax_class = $slug; + } elseif ( ! $greater_reduced_tax_class && strstr( $slug, sanitize_title( $tax_class_slug_names['greater-reduced'] ) ) ) { + $greater_reduced_tax_class = $slug; + } elseif ( ! $super_reduced_tax_class && strstr( $slug, sanitize_title( 'Super reduced rate' ) ) ) { + $super_reduced_tax_class = $slug; + } elseif ( ! $super_reduced_tax_class && strstr( $slug, sanitize_title( $tax_class_slug_names['super-reduced'] ) ) ) { + $super_reduced_tax_class = $slug; + } elseif ( ! $reduced_tax_class && strstr( $slug, sanitize_title( 'Reduced rate' ) ) ) { + $reduced_tax_class = $slug; + } elseif ( ! $reduced_tax_class && strstr( $slug, sanitize_title( $tax_class_slug_names['reduced'] ) ) ) { // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch + $reduced_tax_class = $slug; + } elseif ( ! $reduced_tax_class && strstr( $slug, 'reduced' ) && ! $reduced_tax_class ) { + $reduced_tax_class = $slug; + } + } + + $slugs = array( + 'reduced' => $reduced_tax_class, + 'greater-reduced' => $greater_reduced_tax_class, + 'super-reduced' => $super_reduced_tax_class, + 'standard' => '', + ); + + wp_cache_set( $cache_key, $slugs, 'taxes' ); + } + + return apply_filters( 'woocommerce_eu_tax_helper_tax_rate_class_slugs', $slugs ); + } + + public static function get_tax_type_by_country_rate( $rate_percentage, $country ) { + $country = strtoupper( $country ); + + /** + * Map northern ireland to GB + */ + if ( 'XI' === $country ) { + $country = 'GB'; + } + + $eu_rates = self::get_eu_tax_rates(); + $tax_type = 'standard'; + + if ( array_key_exists( $country, $eu_rates ) ) { + $rates = $eu_rates[ $country ]; + + foreach ( $rates as $rate ) { + foreach ( $rate as $tax_rate_type => $tax_rate_percent ) { + if ( ( is_array( $tax_rate_percent ) && in_array( $rate_percentage, $tax_rate_percent, true ) ) || (float) $tax_rate_percent === (float) $rate_percentage ) { + $tax_type = $tax_rate_type; + break; + } + } + } + } + + return apply_filters( 'woocommerce_eu_tax_helper_country_rate_tax_type', $tax_type, $country, $rate_percentage ); + } + + public static function get_eu_tax_rates() { + /** + * @see https://europa.eu/youreurope/business/taxation/vat/vat-rules-rates/index_en.htm + * + * Include Great Britain to allow including Norther Ireland + */ + $rates = array( + 'AT' => array( + array( + 'standard' => 20, + 'reduced' => array( 10, 13 ), + ), + ), + 'BE' => array( + array( + 'standard' => 21, + 'reduced' => array( 6, 12 ), + ), + ), + 'BG' => array( + array( + 'standard' => 20, + 'reduced' => array( 9 ), + ), + ), + 'CY' => array( + array( + 'standard' => 19, + 'reduced' => array( 5, 9 ), + ), + ), + 'CZ' => array( + array( + 'standard' => 21, + 'reduced' => array( 10, 15 ), + ), + ), + 'DE' => array( + array( + 'standard' => 19, + 'reduced' => array( 7 ), + ), + ), + 'DK' => array( + array( + 'standard' => 25, + 'reduced' => array(), + ), + ), + 'EE' => array( + array( + 'standard' => 20, + 'reduced' => array( 9 ), + ), + ), + 'GR' => array( + array( + 'standard' => 24, + 'reduced' => array( 6, 13 ), + ), + ), + 'ES' => array( + array( + 'standard' => 21, + 'reduced' => array( 10 ), + 'super-reduced' => 4, + ), + ), + 'FI' => array( + array( + 'standard' => 24, + 'reduced' => array( 10, 14 ), + ), + ), + 'FR' => array( + array( + 'standard' => 20, + 'reduced' => array( 5.5, 10 ), + 'super-reduced' => 2.1, + ), + ), + 'HR' => array( + array( + 'standard' => 25, + 'reduced' => array( 5, 13 ), + ), + ), + 'HU' => array( + array( + 'standard' => 27, + 'reduced' => array( 5, 18 ), + ), + ), + 'IE' => array( + array( + 'standard' => 23, + 'reduced' => array( 9, 13.5 ), + 'super-reduced' => 4.8, + ), + ), + 'IT' => array( + array( + 'standard' => 22, + 'reduced' => array( 5, 10 ), + 'super-reduced' => 4, + ), + ), + 'LT' => array( + array( + 'standard' => 21, + 'reduced' => array( 5, 9 ), + ), + ), + 'LU' => array( + array( + 'standard' => 17, + 'reduced' => array( 8 ), + 'super-reduced' => 3, + ), + ), + 'LV' => array( + array( + 'standard' => 21, + 'reduced' => array( 12, 5 ), + ), + ), + 'MC' => array( + array( + 'standard' => 20, + 'reduced' => array( 5.5, 10 ), + 'super-reduced' => 2.1, + ), + ), + 'MT' => array( + array( + 'standard' => 18, + 'reduced' => array( 5, 7 ), + ), + ), + 'NL' => array( + array( + 'standard' => 21, + 'reduced' => array( 9 ), + ), + ), + 'PL' => array( + array( + 'standard' => 23, + 'reduced' => array( 5, 8 ), + ), + ), + 'PT' => array( + array( + // Madeira + 'postcode' => array( '90*', '91*', '92*', '93*', '94*' ), + 'standard' => 22, + 'reduced' => array( 5, 12 ), + 'name' => _x( 'Madeira', 'tax-helper', 'woocommerce-germanized' ), + ), + array( + // Acores + 'postcode' => array( '95*', '96*', '97*', '98*', '99*' ), + 'standard' => 18, + 'reduced' => array( 4, 9 ), + 'name' => _x( 'Acores', 'tax-helper', 'woocommerce-germanized' ), + ), + array( + 'standard' => 23, + 'reduced' => array( 6, 13 ), + ), + ), + 'RO' => array( + array( + 'standard' => 19, + 'reduced' => array( 5, 9 ), + ), + ), + 'SE' => array( + array( + 'standard' => 25, + 'reduced' => array( 6, 12 ), + ), + ), + 'SI' => array( + array( + 'standard' => 22, + 'reduced' => array( 9.5 ), + ), + ), + 'SK' => array( + array( + 'standard' => 20, + 'reduced' => array( 10 ), + ), + ), + 'GB' => array( + array( + 'standard' => 20, + 'reduced' => array( 5 ), + 'postcode' => array( 'BT*' ), + 'name' => _x( 'Northern Ireland', 'tax-helper', 'woocommerce-germanized' ), + ), + ), + ); + + foreach ( self::get_vat_postcode_exemptions_by_country() as $country => $exempt_postcodes ) { + if ( array_key_exists( $country, $rates ) ) { + $default_rate = array_values( $rates[ $country ] )[0]; + + $postcode_exempt = array( + 'postcode' => $exempt_postcodes, + 'standard' => 0, + 'reduced' => count( $default_rate['reduced'] ) > 1 ? array( 0, 0 ) : array( 0 ), + 'name' => _x( 'Exempt', 'tax-helper-rate-import', 'woocommerce-germanized' ), + 'is_exempt' => true, + ); + + if ( array_key_exists( 'super-reduced', $default_rate ) ) { + $postcode_exempt['super-reduced'] = 0; + } + + // Prepend before other tax rates + $rates[ $country ] = array_merge( array( $postcode_exempt ), $rates[ $country ] ); + } + } + + return $rates; + } + + /** + * @param \stdClass $rate + * + * @return bool + */ + public static function tax_rate_is_northern_ireland( $rate ) { + if ( 'GB' === $rate->tax_rate_country && isset( $rate->postcode ) && ! empty( $rate->postcode ) ) { + foreach ( $rate->postcode as $postcode ) { + if ( self::is_northern_ireland( $rate->tax_rate_country, $postcode ) ) { + return true; + } + } + } + + return false; + } + + public static function import_rates( $rates, $tax_class = '' ) { + global $wpdb; + + $eu_countries = self::get_eu_vat_countries(); + + /** + * Delete EU tax rates and make sure tax rate locations are deleted too + */ + foreach ( \WC_Tax::get_rates_for_tax_class( $tax_class ) as $rate_id => $rate ) { + if ( in_array( $rate->tax_rate_country, $eu_countries, true ) || self::tax_rate_is_northern_ireland( $rate ) || ( 'GB' === $rate->tax_rate_country && 'GB' !== self::get_base_country() ) ) { + \WC_Tax::_delete_tax_rate( $rate_id ); + } + } + + $count = 0; + + foreach ( $rates as $rate ) { + $rate = wp_parse_args( + $rate, + array( + 'rate' => 0, + 'country' => '', + 'postcode' => '', + 'name' => '', + ) + ); + + $iso = wc_strtoupper( $rate['country'] ); + $vat_desc = $iso; + + if ( ! empty( $rate['name'] ) ) { + $vat_desc = $vat_desc . ' ' . $rate['name']; + } + + $vat_rate = wc_format_decimal( $rate['rate'], false, true ); + + $tax_rate_name = apply_filters( 'woocommerce_eu_tax_helper_import_tax_rate_name', sprintf( _x( 'VAT %1$s %% %2$s', 'tax-helper-rate-import', 'woocommerce-germanized' ), $vat_rate, $vat_desc ), $rate['rate'], $iso, $tax_class, $rate ); + + $_tax_rate = array( + 'tax_rate_country' => $iso, + 'tax_rate_state' => '', + 'tax_rate' => (string) number_format( (float) wc_clean( $rate['rate'] ), 4, '.', '' ), + 'tax_rate_name' => $tax_rate_name, + 'tax_rate_compound' => 0, + 'tax_rate_priority' => 1, + 'tax_rate_order' => $count++, + 'tax_rate_shipping' => ( strstr( $tax_class, 'virtual' ) ? 0 : 1 ), + 'tax_rate_class' => $tax_class, + ); + + $new_tax_rate_id = \WC_Tax::_insert_tax_rate( $_tax_rate ); + + if ( ! empty( $rate['postcode'] ) ) { + \WC_Tax::_update_tax_rate_postcodes( $new_tax_rate_id, $rate['postcode'] ); + } + } + } + + /** + * @param $rate_id + * @param \WC_Order $order + */ + public static function get_tax_rate_percent( $rate_id, $order ) { + $taxes = $order->get_taxes(); + $percentage = null; + + foreach ( $taxes as $tax ) { + if ( (int) $tax->get_rate_id() === (int) $rate_id ) { + if ( is_callable( array( $tax, 'get_rate_percent' ) ) ) { + $percentage = $tax->get_rate_percent(); + } + } + } + + /** + * WC_Order_Item_Tax::get_rate_percent returns null by default. + * Fallback to global tax rates (DB) in case the percentage is not available within order data. + */ + if ( is_null( $percentage ) || '' === $percentage ) { + $rate_percentage = self::get_tax_rate_percentage( $rate_id ); + + if ( false !== $rate_percentage ) { + $percentage = $rate_percentage; + } + } + + if ( ! is_numeric( $percentage ) ) { + $percentage = 0; + } + + return $percentage; + } + + public static function get_tax_rate_percentage( $rate_id ) { + $percentage = false; + + if ( is_callable( array( 'WC_Tax', 'get_rate_percent_value' ) ) ) { + $percentage = \WC_Tax::get_rate_percent_value( $rate_id ); + } elseif ( is_callable( array( 'WC_Tax', 'get_rate_percent' ) ) ) { + $percentage = filter_var( \WC_Tax::get_rate_percent( $rate_id ), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION ); + } + + return $percentage; + } +} diff --git a/packages/woocommerce-germanized-dhl/assets/css/admin.css b/packages/woocommerce-germanized-dhl/assets/css/admin.css new file mode 100644 index 000000000..30fa46b20 --- /dev/null +++ b/packages/woocommerce-germanized-dhl/assets/css/admin.css @@ -0,0 +1,48 @@ +.germanized-create-label .wc-gzd-shipment-im-additional-services p.label { + margin-top: 10px; + width: 100%; + display: block; + margin-bottom: 5px; + font-weight: bold; } + +.germanized-create-label .wc-gzd-dhl-im-product-data { + margin-top: 2em; + min-width: 700px; + margin-left: -1rem !important; + margin-right: -1rem !important; } + .germanized-create-label .wc-gzd-dhl-im-product-data .column { + padding-left: 1rem !important; + padding-right: 1rem !important; } + .germanized-create-label .wc-gzd-dhl-im-product-data .column p:first-child { + margin-top: 1.5em !important; } + .germanized-create-label .wc-gzd-dhl-im-product-data .wc-gzd-dhl-im-product-price { + background: #ffd633; + border-radius: 4px; + padding: .5em 1em; } + .germanized-create-label .wc-gzd-dhl-im-product-data .wc-gzd-dhl-im-product-price .amount { + font-size: 18px; + font-weight: bold; } + .germanized-create-label .wc-gzd-dhl-im-product-data .wc-gzd-dhl-im-product-price .price-suffix { + display: block; + font-size: 11px; + line-height: 15px; } + .germanized-create-label .wc-gzd-dhl-im-product-data .col-dimensions { + color: #999; } + .germanized-create-label .wc-gzd-dhl-im-product-data .col-preview .image-preview img { + height: auto; + max-height: 140px; } + .germanized-create-label .wc-gzd-dhl-im-product-data .wc-gzd-dhl-im-product-information-text, .germanized-create-label .wc-gzd-dhl-im-product-data .wc-gzd-dhl-im-product-description { + font-size: 11px; + color: #999; + line-height: 1.5em; } + +.germanized-create-label .show-services-trigger { + font-weight: bold; + margin-top: 15px; + margin-bottom: 0; + display: block; + text-align: right; + vertical-align: middle; + line-height: 20px; } + .germanized-create-label .show-services-trigger a { + text-decoration: none; } \ No newline at end of file diff --git a/packages/woocommerce-germanized-dhl/assets/css/admin.min.css b/packages/woocommerce-germanized-dhl/assets/css/admin.min.css new file mode 100644 index 000000000..59195f1cd --- /dev/null +++ b/packages/woocommerce-germanized-dhl/assets/css/admin.min.css @@ -0,0 +1 @@ +.germanized-create-label .wc-gzd-shipment-im-additional-services p.label{margin-top:10px;width:100%;display:block;margin-bottom:5px;font-weight:700}.germanized-create-label .wc-gzd-dhl-im-product-data{margin-top:2em;min-width:700px;margin-left:-1rem!important;margin-right:-1rem!important}.germanized-create-label .wc-gzd-dhl-im-product-data .column{padding-left:1rem!important;padding-right:1rem!important}.germanized-create-label .wc-gzd-dhl-im-product-data .column p:first-child{margin-top:1.5em!important}.germanized-create-label .wc-gzd-dhl-im-product-data .wc-gzd-dhl-im-product-price{background:#ffd633;border-radius:4px;padding:.5em 1em}.germanized-create-label .wc-gzd-dhl-im-product-data .wc-gzd-dhl-im-product-price .amount{font-size:18px;font-weight:700}.germanized-create-label .wc-gzd-dhl-im-product-data .wc-gzd-dhl-im-product-price .price-suffix{display:block;font-size:11px;line-height:15px}.germanized-create-label .wc-gzd-dhl-im-product-data .col-dimensions{color:#999}.germanized-create-label .wc-gzd-dhl-im-product-data .col-preview .image-preview img{height:auto;max-height:140px}.germanized-create-label .wc-gzd-dhl-im-product-data .wc-gzd-dhl-im-product-description,.germanized-create-label .wc-gzd-dhl-im-product-data .wc-gzd-dhl-im-product-information-text{font-size:11px;color:#999;line-height:1.5em}.germanized-create-label .show-services-trigger{font-weight:700;margin-top:15px;margin-bottom:0;display:block;text-align:right;vertical-align:middle;line-height:20px}.germanized-create-label .show-services-trigger a{text-decoration:none} \ No newline at end of file diff --git a/packages/woocommerce-germanized-dhl/assets/css/admin.scss b/packages/woocommerce-germanized-dhl/assets/css/admin.scss new file mode 100644 index 000000000..32abfae9b --- /dev/null +++ b/packages/woocommerce-germanized-dhl/assets/css/admin.scss @@ -0,0 +1,76 @@ +.germanized-create-label { + .wc-gzd-shipment-im-additional-services { + p.label { + margin-top: 10px; + width: 100%; + display: block; + margin-bottom: 5px; + font-weight: bold; + } + } + + .wc-gzd-dhl-im-product-data { + margin-top: 2em; + min-width: 700px; + margin-left: -1rem !important; + margin-right: -1rem !important; + + .column { + padding-left: 1rem !important; + padding-right: 1rem !important; + + p:first-child { + margin-top: 1.5em !important; + } + } + + .wc-gzd-dhl-im-product-price { + background: #ffd633; + border-radius: 4px; + padding: .5em 1em; + + .amount { + font-size: 18px; + font-weight: bold; + } + .price-suffix { + display: block; + font-size: 11px; + line-height: 15px; + } + } + + .col-dimensions { + color: #999; + } + + .col-preview { + .image-preview { + img { + height: auto; + max-height: 140px; + } + } + } + + .wc-gzd-dhl-im-product-information-text, .wc-gzd-dhl-im-product-description { + font-size: 11px; + color: #999; + line-height: 1.5em; + } + } + + .show-services-trigger { + font-weight: bold; + margin-top: 15px; + margin-bottom: 0; + display: block; + text-align: right; + vertical-align: middle; + line-height: 20px; + + a { + text-decoration: none; + } + } +} \ No newline at end of file diff --git a/packages/woocommerce-germanized-dhl/assets/css/parcel-finder.css b/packages/woocommerce-germanized-dhl/assets/css/parcel-finder.css new file mode 100644 index 000000000..1fad22ff7 --- /dev/null +++ b/packages/woocommerce-germanized-dhl/assets/css/parcel-finder.css @@ -0,0 +1,155 @@ +#dhl-parcel-finder-wrapper { + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + transform: translateZ(0); + width: 100%; + height: 100%; + left: 0; + position: fixed; + top: 0; + z-index: 99992; + visibility: hidden; } + #dhl-parcel-finder-wrapper * { + box-sizing: border-box; } + #dhl-parcel-finder-wrapper #dhl-parcel-finder-bg-overlay { + background: #1e1e1e; + opacity: 0; + transition-duration: inherit; + transition-property: opacity; + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; } + #dhl-parcel-finder-wrapper.open { + visibility: visible; } + #dhl-parcel-finder-wrapper.open #dhl-parcel-finder-bg-overlay { + opacity: .87; + transition-timing-function: cubic-bezier(0.22, 0.61, 0.36, 1); } + #dhl-parcel-finder-wrapper #dhl-parcel-finder-inner { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + overflow: hidden; + z-index: 99994; } + #dhl-parcel-finder-wrapper #dhl-parcel-finder-inner-wrapper { + padding: 6px 6px 0; + display: block; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + height: 100%; + left: 0; + outline: none; + overflow: auto; + -webkit-overflow-scrolling: touch; + position: absolute; + text-align: center; + top: 0; + transition-property: transform,opacity; + white-space: normal; + width: 100%; + z-index: 99994; } + #dhl-parcel-finder-wrapper #dhl-parcel-finder-inner-wrapper::before { + content: ""; + display: inline-block; + height: 100%; + margin-right: -.25em; + vertical-align: middle; + width: 0; } + #dhl-parcel-finder-wrapper #dhl-parcel-finder-inner-wrapper #dhl-parcel-finder { + width: 95%; + height: 95%; + display: inline-block; + background: #fff; + margin: 0 0 6px; + max-width: 100%; + overflow: auto; + padding: 34px; + position: relative; + text-align: left; + vertical-align: middle; } + #dhl-parcel-finder-wrapper .dhl-parcel-finder-close { + background: transparent; + border: 0; + border-radius: 0; + color: #555; + cursor: pointer; + height: 44px; + margin: 0; + padding: 6px; + position: absolute; + right: 0; + top: 0; + width: 44px; + z-index: 10; } + #dhl-parcel-finder-wrapper .dhl-parcel-finder-close svg { + fill: transparent; + opacity: .8; + stroke: currentColor; + stroke-width: 1.5; + transition: stroke .1s; } + #dhl-parcel-finder-wrapper #dhl-parcel-finder-map { + width: 100%; + height: 85%; + position: relative !important; } + #dhl-parcel-finder-wrapper #dhl-parcel-finder-map #parcel-content #bodyContent { + line-height: 1.5em; } + #dhl-parcel-finder-wrapper #dhl-parcel-finder-map #parcel-content address { + margin-bottom: 0; } + #dhl-parcel-finder-wrapper #dhl-parcel-finder-map #parcel-content .parcel-title { + padding-top: 0; + margin-bottom: .5em; } + #dhl-parcel-finder-wrapper #dhl-parcel-finder-map #parcel-content .parcel-subtitle { + font-size: 0.8125rem; + color: #767676; + font-weight: 800; + letter-spacing: 0.15em; + text-transform: uppercase; + padding: 1em 0 0; } + #dhl-parcel-finder-wrapper #dhl-parcel-finder-map #parcel-content .dhl-parcelshop-select-btn { + width: 100%; + margin-top: 10px; } + #dhl-parcel-finder-wrapper form#dhl-parcel-finder-form { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + align-items: center; } + #dhl-parcel-finder-wrapper form#dhl-parcel-finder-form .form-field { + margin-right: 1.5em; } + #dhl-parcel-finder-wrapper form#dhl-parcel-finder-form .form-field.large { + min-width: 20%; } + #dhl-parcel-finder-wrapper form#dhl-parcel-finder-form .form-field.finder-pickup-type { + margin-right: 25px; + min-width: 150px; + display: flex; + align-items: center; } + #dhl-parcel-finder-wrapper form#dhl-parcel-finder-form .form-field.finder-pickup-type.hidden { + display: none; } + #dhl-parcel-finder-wrapper form#dhl-parcel-finder-form .form-field.finder-pickup-type .icon { + width: 40px; + height: 40px; + display: inline-block; + background-repeat: no-repeat; + background-size: contain; + margin-left: 10px; } + #dhl-parcel-finder-wrapper form#dhl-parcel-finder-form .form-field#dhl-search-button { + text-align: right; + margin-right: 0; } + #dhl-parcel-finder-wrapper form#dhl-parcel-finder-form .form-field#dhl-search-button .button { + width: 100%; + margin: 0; } + +@media (max-width: 700px) { + #dhl-parcel-finder-wrapper form#dhl-parcel-finder-form .form-field { + width: 100%; + margin-right: 0; } + #dhl-parcel-finder-wrapper form#dhl-parcel-finder-form .form-field.packstation, #dhl-parcel-finder-wrapper form#dhl-parcel-finder-form .form-field.parcelshop { + width: auto; + margin-right: 1.5em; } + #dhl-parcel-finder-wrapper form#dhl-parcel-finder-form .form-field#dhl-search-button { + text-align: left; } + #dhl-parcel-finder-wrapper form#dhl-parcel-finder-form .form-field#dhl-search-button .button { + width: 100%; + margin: 0; } } \ No newline at end of file diff --git a/packages/woocommerce-germanized-dhl/assets/css/parcel-finder.min.css b/packages/woocommerce-germanized-dhl/assets/css/parcel-finder.min.css new file mode 100644 index 000000000..555775f6e --- /dev/null +++ b/packages/woocommerce-germanized-dhl/assets/css/parcel-finder.min.css @@ -0,0 +1 @@ +#dhl-parcel-finder-wrapper{-webkit-backface-visibility:hidden;backface-visibility:hidden;transform:translateZ(0);width:100%;height:100%;left:0;position:fixed;top:0;z-index:99992;visibility:hidden}#dhl-parcel-finder-wrapper *{box-sizing:border-box}#dhl-parcel-finder-wrapper #dhl-parcel-finder-bg-overlay{background:#1e1e1e;opacity:0;transition-duration:inherit;transition-property:opacity;bottom:0;left:0;position:absolute;right:0;top:0}#dhl-parcel-finder-wrapper.open{visibility:visible}#dhl-parcel-finder-wrapper.open #dhl-parcel-finder-bg-overlay{opacity:.87;transition-timing-function:cubic-bezier(.22,.61,.36,1)}#dhl-parcel-finder-wrapper #dhl-parcel-finder-inner{bottom:0;left:0;position:absolute;right:0;top:0;overflow:hidden;z-index:99994}#dhl-parcel-finder-wrapper #dhl-parcel-finder-inner-wrapper{padding:6px 6px 0;display:block;-webkit-backface-visibility:hidden;backface-visibility:hidden;height:100%;left:0;outline:0;overflow:auto;-webkit-overflow-scrolling:touch;position:absolute;text-align:center;top:0;transition-property:transform,opacity;white-space:normal;width:100%;z-index:99994}#dhl-parcel-finder-wrapper #dhl-parcel-finder-inner-wrapper::before{content:"";display:inline-block;height:100%;margin-right:-.25em;vertical-align:middle;width:0}#dhl-parcel-finder-wrapper #dhl-parcel-finder-inner-wrapper #dhl-parcel-finder{width:95%;height:95%;display:inline-block;background:#fff;margin:0 0 6px;max-width:100%;overflow:auto;padding:34px;position:relative;text-align:left;vertical-align:middle}#dhl-parcel-finder-wrapper .dhl-parcel-finder-close{background:0 0;border:0;border-radius:0;color:#555;cursor:pointer;height:44px;margin:0;padding:6px;position:absolute;right:0;top:0;width:44px;z-index:10}#dhl-parcel-finder-wrapper .dhl-parcel-finder-close svg{fill:transparent;opacity:.8;stroke:currentColor;stroke-width:1.5;transition:stroke .1s}#dhl-parcel-finder-wrapper #dhl-parcel-finder-map{width:100%;height:85%;position:relative!important}#dhl-parcel-finder-wrapper #dhl-parcel-finder-map #parcel-content #bodyContent{line-height:1.5em}#dhl-parcel-finder-wrapper #dhl-parcel-finder-map #parcel-content address{margin-bottom:0}#dhl-parcel-finder-wrapper #dhl-parcel-finder-map #parcel-content .parcel-title{padding-top:0;margin-bottom:.5em}#dhl-parcel-finder-wrapper #dhl-parcel-finder-map #parcel-content .parcel-subtitle{font-size:.8125rem;color:#767676;font-weight:800;letter-spacing:.15em;text-transform:uppercase;padding:1em 0 0}#dhl-parcel-finder-wrapper #dhl-parcel-finder-map #parcel-content .dhl-parcelshop-select-btn{width:100%;margin-top:10px}#dhl-parcel-finder-wrapper form#dhl-parcel-finder-form{display:flex;flex-wrap:wrap;justify-content:flex-start;align-items:center}#dhl-parcel-finder-wrapper form#dhl-parcel-finder-form .form-field{margin-right:1.5em}#dhl-parcel-finder-wrapper form#dhl-parcel-finder-form .form-field.large{min-width:20%}#dhl-parcel-finder-wrapper form#dhl-parcel-finder-form .form-field.finder-pickup-type{margin-right:25px;min-width:150px;display:flex;align-items:center}#dhl-parcel-finder-wrapper form#dhl-parcel-finder-form .form-field.finder-pickup-type.hidden{display:none}#dhl-parcel-finder-wrapper form#dhl-parcel-finder-form .form-field.finder-pickup-type .icon{width:40px;height:40px;display:inline-block;background-repeat:no-repeat;background-size:contain;margin-left:10px}#dhl-parcel-finder-wrapper form#dhl-parcel-finder-form .form-field#dhl-search-button{text-align:right;margin-right:0}#dhl-parcel-finder-wrapper form#dhl-parcel-finder-form .form-field#dhl-search-button .button{width:100%;margin:0}@media (max-width:700px){#dhl-parcel-finder-wrapper form#dhl-parcel-finder-form .form-field{width:100%;margin-right:0}#dhl-parcel-finder-wrapper form#dhl-parcel-finder-form .form-field.packstation,#dhl-parcel-finder-wrapper form#dhl-parcel-finder-form .form-field.parcelshop{width:auto;margin-right:1.5em}#dhl-parcel-finder-wrapper form#dhl-parcel-finder-form .form-field#dhl-search-button{text-align:left}#dhl-parcel-finder-wrapper form#dhl-parcel-finder-form .form-field#dhl-search-button .button{width:100%;margin:0}} \ No newline at end of file diff --git a/packages/woocommerce-germanized-dhl/assets/css/parcel-finder.scss b/packages/woocommerce-germanized-dhl/assets/css/parcel-finder.scss new file mode 100644 index 000000000..9a7c9833b --- /dev/null +++ b/packages/woocommerce-germanized-dhl/assets/css/parcel-finder.scss @@ -0,0 +1,218 @@ +#dhl-parcel-finder-wrapper { + backface-visibility: hidden; + transform: translateZ(0); + width: 100%; + height: 100%; + left: 0; + position: fixed; + top: 0; + z-index: 99992; + visibility: hidden; + + * { + box-sizing: border-box; + } + + #dhl-parcel-finder-bg-overlay { + background: #1e1e1e; + opacity: 0; + transition-duration: inherit; + transition-property: opacity; + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + } + + &.open { + visibility: visible; + + #dhl-parcel-finder-bg-overlay { + opacity: .87; + transition-timing-function: cubic-bezier(.22,.61,.36,1); + } + } + + #dhl-parcel-finder-inner { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + overflow: hidden; + z-index: 99994; + } + + #dhl-parcel-finder-inner-wrapper { + padding: 6px 6px 0; + display: block; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + height: 100%; + left: 0; + outline: none; + overflow: auto; + -webkit-overflow-scrolling: touch; + position: absolute; + text-align: center; + top: 0; + transition-property: transform,opacity; + white-space: normal; + width: 100%; + z-index: 99994; + + &::before { + content: ""; + display: inline-block; + height: 100%; + margin-right: -.25em; + vertical-align: middle; + width: 0; + } + + #dhl-parcel-finder { + width: 95%; + height: 95%; + display: inline-block; + background: #fff; + margin: 0 0 6px; + max-width: 100%; + overflow: auto; + padding: 34px; + position: relative; + text-align: left; + vertical-align: middle; + } + } + + .dhl-parcel-finder-close { + background: transparent; + border: 0; + border-radius: 0; + color: #555; + cursor: pointer; + height: 44px; + margin: 0; + padding: 6px; + position: absolute; + right: 0; + top: 0; + width: 44px; + z-index: 10; + + svg { + fill: transparent; + opacity: .8; + stroke: currentColor; + stroke-width: 1.5; + transition: stroke .1s; + } + } + + #dhl-parcel-finder-map { + width: 100%; + height: 85%; + position: relative !important; + + #parcel-content { + + #bodyContent { + line-height: 1.5em; + } + + address { + margin-bottom: 0; + } + + .parcel-title { + padding-top: 0; + margin-bottom: .5em; + } + + .parcel-subtitle { + font-size: 0.8125rem; + color: #767676; + font-weight: 800; + letter-spacing: 0.15em; + text-transform: uppercase; + padding: 1em 0 0; + } + + .dhl-parcelshop-select-btn { + width: 100%; + margin-top: 10px; + } + } + } + + form#dhl-parcel-finder-form { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + align-items: center; + + .form-field { + margin-right: 1.5em; + + &.large { + min-width: 20%; + } + + &.finder-pickup-type { + margin-right: 25px; + min-width: 150px; + display: flex; + align-items: center; + + &.hidden { + display: none; + } + + .icon { + width: 40px; + height: 40px; + display: inline-block; + background-repeat: no-repeat; + background-size: contain; + margin-left: 10px; + } + } + + &#dhl-search-button { + text-align: right; + margin-right: 0; + + .button { + width: 100%; + margin: 0; + } + } + } + } +} + +@media( max-width: 700px ) { + #dhl-parcel-finder-wrapper { + form#dhl-parcel-finder-form { + .form-field { + width: 100%; + margin-right: 0; + + &.packstation, &.parcelshop { + width: auto; + margin-right: 1.5em; + } + + &#dhl-search-button { + text-align: left; + + .button { + width: 100%; + margin: 0; + } + } + } + } + } +} \ No newline at end of file diff --git a/packages/woocommerce-germanized-dhl/assets/css/preferred-services.css b/packages/woocommerce-germanized-dhl/assets/css/preferred-services.css new file mode 100644 index 000000000..636d53a33 --- /dev/null +++ b/packages/woocommerce-germanized-dhl/assets/css/preferred-services.css @@ -0,0 +1,156 @@ +#tiptip_holder { + display: none; + z-index: 8675309; + position: absolute; + top: 0; + /*rtl:ignore*/ + left: 0; } + #tiptip_holder.tip_top { + padding-bottom: 5px; } + #tiptip_holder.tip_top #tiptip_arrow_inner { + margin-top: -7px; + margin-left: -6px; + border-top-color: #333; } + #tiptip_holder.tip_bottom { + padding-top: 5px; } + #tiptip_holder.tip_bottom #tiptip_arrow_inner { + margin-top: -5px; + margin-left: -6px; + border-bottom-color: #333; } + #tiptip_holder.tip_right { + padding-left: 5px; } + #tiptip_holder.tip_right #tiptip_arrow_inner { + margin-top: -6px; + margin-left: -5px; + border-right-color: #333; } + #tiptip_holder.tip_left { + padding-right: 5px; } + #tiptip_holder.tip_left #tiptip_arrow_inner { + margin-top: -6px; + margin-left: -7px; + border-left-color: #333; } + +#tiptip_content { + color: #fff; + font-size: 0.8em; + max-width: 150px; + background: #333; + text-align: center; + border-radius: 3px; + padding: 0.618em 1em; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); } + #tiptip_content code { + padding: 1px; + background: #888; } + +#tiptip_arrow, +#tiptip_arrow_inner { + position: absolute; + border-color: transparent; + border-style: solid; + border-width: 6px; + height: 0; + width: 0; } + +.dhl-preferred-service-content { + margin-top: 1em; } + .dhl-preferred-service-content .dhl-hidden { + display: none; } + .dhl-preferred-service-content .dhl-preferred-service-cost { + font-size: .9em; } + .dhl-preferred-service-content .dhl-preferred-service-item { + margin-bottom: 1em; } + .dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-service-logo { + margin-bottom: 1em; } + .dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-service-logo img { + margin: 0; + padding: 0; + max-height: 100px; + max-width: 100px; + background: #FFCC00; } + .dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-service-title { + font-weight: bold; + font-size: 1em; + margin-bottom: .5em; } + .dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-service-cost { + margin-bottom: .5em; } + .dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-service-desc { + font-size: .9em; + margin-bottom: .5em; } + .dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-service-times { + display: flex; + flex-direction: row; + flex-wrap: wrap; + margin: 0; + padding: 0; } + .dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-service-times li { + flex-basis: 10%; + display: inline-block; + text-align: center; + padding: 10px 0 0; + margin: 0 8px 8px 0; + background-color: #e3e3e3; } + .dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-service-times li label { + position: relative; + display: flex; + flex-direction: column; + flex-wrap: wrap; + padding: 5px 10px; + font-size: .9em; + font-weight: bold; + background-color: #eef4f2; + cursor: pointer; + margin: 0; + color: #5f7285; } + .dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-service-times li label .dhl-preferred-time-title { + font-size: 1.2em; } + .dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-service-times li input[type=radio] { + opacity: 0; + width: 1px; + height: 1px; + position: absolute; } + .dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-service-times li input[type=radio]:checked ~ label { + background-color: #FFCC00; } + .dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-service-times.dhl-preferred-service-time li { + flex-grow: inherit; + flex-basis: inherit; } + .dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-service-times.dhl-preferred-service-time li label .dhl-preferred-time-title { + font-size: 1em; } + .dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-service-data input[type=text] { + width: 100%; + margin-bottom: .5em; } + .dhl-preferred-service-content .dhl-preferred-service-item .woocommerce-help-tip { + background: #ffcc00; + display: inline-block; + font-size: 1em; + font-style: normal; + height: 18px; + padding: 3px; + margin-top: -5px; + margin-left: 5px; + border-radius: 50%; + line-height: 18px; + position: relative; + vertical-align: middle; + width: 18px; } + .dhl-preferred-service-content .dhl-preferred-service-item .woocommerce-help-tip::after { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + text-align: center; + cursor: help; + content: "?"; } + .dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-location-types { + list-style: none; + margin: 0; + margin-bottom: 1em; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + align-items: center; } + .dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-location-types li { + margin-right: 1em; } + .dhl-preferred-service-content .dhl-preferred-service-item.dhl-preferred-service-header .dhl-preferred-service-title { + font-size: 1.1em; } \ No newline at end of file diff --git a/packages/woocommerce-germanized-dhl/assets/css/preferred-services.min.css b/packages/woocommerce-germanized-dhl/assets/css/preferred-services.min.css new file mode 100644 index 000000000..d67a6a0b3 --- /dev/null +++ b/packages/woocommerce-germanized-dhl/assets/css/preferred-services.min.css @@ -0,0 +1 @@ +#tiptip_holder{display:none;z-index:8675309;position:absolute;top:0;left:0}#tiptip_holder.tip_top{padding-bottom:5px}#tiptip_holder.tip_top #tiptip_arrow_inner{margin-top:-7px;margin-left:-6px;border-top-color:#333}#tiptip_holder.tip_bottom{padding-top:5px}#tiptip_holder.tip_bottom #tiptip_arrow_inner{margin-top:-5px;margin-left:-6px;border-bottom-color:#333}#tiptip_holder.tip_right{padding-left:5px}#tiptip_holder.tip_right #tiptip_arrow_inner{margin-top:-6px;margin-left:-5px;border-right-color:#333}#tiptip_holder.tip_left{padding-right:5px}#tiptip_holder.tip_left #tiptip_arrow_inner{margin-top:-6px;margin-left:-7px;border-left-color:#333}#tiptip_content{color:#fff;font-size:.8em;max-width:150px;background:#333;text-align:center;border-radius:3px;padding:.618em 1em;box-shadow:0 1px 3px rgba(0,0,0,.2)}#tiptip_content code{padding:1px;background:#888}#tiptip_arrow,#tiptip_arrow_inner{position:absolute;border-color:transparent;border-style:solid;border-width:6px;height:0;width:0}.dhl-preferred-service-content{margin-top:1em}.dhl-preferred-service-content .dhl-hidden{display:none}.dhl-preferred-service-content .dhl-preferred-service-cost{font-size:.9em}.dhl-preferred-service-content .dhl-preferred-service-item{margin-bottom:1em}.dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-service-logo{margin-bottom:1em}.dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-service-logo img{margin:0;padding:0;max-height:100px;max-width:100px;background:#fc0}.dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-service-title{font-weight:700;font-size:1em;margin-bottom:.5em}.dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-service-cost{margin-bottom:.5em}.dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-service-desc{font-size:.9em;margin-bottom:.5em}.dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-service-times{display:flex;flex-direction:row;flex-wrap:wrap;margin:0;padding:0}.dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-service-times li{flex-basis:10%;display:inline-block;text-align:center;padding:10px 0 0;margin:0 8px 8px 0;background-color:#e3e3e3}.dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-service-times li label{position:relative;display:flex;flex-direction:column;flex-wrap:wrap;padding:5px 10px;font-size:.9em;font-weight:700;background-color:#eef4f2;cursor:pointer;margin:0;color:#5f7285}.dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-service-times li label .dhl-preferred-time-title{font-size:1.2em}.dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-service-times li input[type=radio]{opacity:0;width:1px;height:1px;position:absolute}.dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-service-times li input[type=radio]:checked~label{background-color:#fc0}.dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-service-times.dhl-preferred-service-time li{flex-grow:inherit;flex-basis:inherit}.dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-service-times.dhl-preferred-service-time li label .dhl-preferred-time-title{font-size:1em}.dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-service-data input[type=text]{width:100%;margin-bottom:.5em}.dhl-preferred-service-content .dhl-preferred-service-item .woocommerce-help-tip{background:#fc0;display:inline-block;font-size:1em;font-style:normal;height:18px;padding:3px;margin-top:-5px;margin-left:5px;border-radius:50%;line-height:18px;position:relative;vertical-align:middle;width:18px}.dhl-preferred-service-content .dhl-preferred-service-item .woocommerce-help-tip::after{position:absolute;top:0;left:0;width:100%;height:100%;text-align:center;cursor:help;content:"?"}.dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-location-types{list-style:none;margin:0;margin-bottom:1em;display:flex;flex-wrap:wrap;justify-content:flex-start;align-items:center}.dhl-preferred-service-content .dhl-preferred-service-item .dhl-preferred-location-types li{margin-right:1em}.dhl-preferred-service-content .dhl-preferred-service-item.dhl-preferred-service-header .dhl-preferred-service-title{font-size:1.1em} \ No newline at end of file diff --git a/packages/woocommerce-germanized-dhl/assets/css/preferred-services.scss b/packages/woocommerce-germanized-dhl/assets/css/preferred-services.scss new file mode 100644 index 000000000..1890f47d4 --- /dev/null +++ b/packages/woocommerce-germanized-dhl/assets/css/preferred-services.scss @@ -0,0 +1,230 @@ +#tiptip_holder { + display: none; + z-index: 8675309; + position: absolute; + top: 0; + + /*rtl:ignore*/ + left: 0; + + &.tip_top { + padding-bottom: 5px; + + #tiptip_arrow_inner { + margin-top: -7px; + margin-left: -6px; + border-top-color: #333; + } + } + + &.tip_bottom { + padding-top: 5px; + + #tiptip_arrow_inner { + margin-top: -5px; + margin-left: -6px; + border-bottom-color: #333; + } + } + + &.tip_right { + padding-left: 5px; + + #tiptip_arrow_inner { + margin-top: -6px; + margin-left: -5px; + border-right-color: #333; + } + } + + &.tip_left { + padding-right: 5px; + + #tiptip_arrow_inner { + margin-top: -6px; + margin-left: -7px; + border-left-color: #333; + } + } +} + +#tiptip_content { + color: #fff; + font-size: 0.8em; + max-width: 150px; + background: #333; + text-align: center; + border-radius: 3px; + padding: 0.618em 1em; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); + + code { + padding: 1px; + background: #888; + } +} + +#tiptip_arrow, +#tiptip_arrow_inner { + position: absolute; + border-color: transparent; + border-style: solid; + border-width: 6px; + height: 0; + width: 0; +} + +.dhl-preferred-service-content { + margin-top: 1em; + + .dhl-hidden { + display: none; + } + + .dhl-preferred-service-cost { + font-size: .9em; + } + + .dhl-preferred-service-item { + margin-bottom: 1em; + + .dhl-preferred-service-logo { + img { + margin: 0; + padding: 0; + max-height: 100px; + max-width: 100px; + background: #FFCC00; + } + margin-bottom: 1em; + } + + .dhl-preferred-service-title { + font-weight: bold; + font-size: 1em; + margin-bottom: .5em; + } + + .dhl-preferred-service-cost { + margin-bottom: .5em; + } + + .dhl-preferred-service-desc { + font-size: .9em; + margin-bottom: .5em; + } + + .dhl-preferred-service-times { + display: flex; + flex-direction: row; + flex-wrap: wrap; + margin: 0; + padding: 0; + + li { + flex-basis: 10%; + display: inline-block; + text-align: center; + padding: 10px 0 0; + margin: 0 8px 8px 0; + background-color: #e3e3e3; + + label { + position: relative; + display: flex; + flex-direction: column; + flex-wrap: wrap; + padding: 5px 10px; + font-size: .9em; + font-weight: bold; + background-color: #eef4f2; + cursor: pointer; + margin: 0; + color: #5f7285; + + .dhl-preferred-time-title { + font-size: 1.2em; + } + } + + input[type=radio] { + opacity: 0; + width: 1px; + height: 1px; + position: absolute; + + &:checked ~ label { + background-color: #FFCC00; + } + } + } + + &.dhl-preferred-service-time { + li { + flex-grow: inherit; + flex-basis: inherit; + + label { + .dhl-preferred-time-title { + font-size: 1em; + } + } + } + } + } + + .dhl-preferred-service-data { + input[type=text] { + width: 100%; + margin-bottom: .5em; + } + } + + .woocommerce-help-tip { + background: #ffcc00; + display: inline-block; + font-size: 1em; + font-style: normal; + height: 18px; + padding: 3px; + margin-top: -5px; + margin-left: 5px; + border-radius: 50%; + line-height: 18px; + position: relative; + vertical-align: middle; + width: 18px; + + &::after { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + text-align: center; + cursor: help; + content: "?"; + } + } + + .dhl-preferred-location-types { + list-style: none; + margin: 0; + margin-bottom: 1em; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + align-items: center; + + li { + margin-right: 1em; + } + } + + &.dhl-preferred-service-header { + .dhl-preferred-service-title { + font-size: 1.1em; + } + } + } +} \ No newline at end of file diff --git a/packages/woocommerce-germanized-dhl/assets/img/dhl-official.png b/packages/woocommerce-germanized-dhl/assets/img/dhl-official.png new file mode 100755 index 0000000000000000000000000000000000000000..18dab3cf6209f060a111015fd08fedcc2fe59436 GIT binary patch literal 41839 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 literal 0 HcmV?d00001 diff --git a/packages/woocommerce-germanized-dhl/assets/img/packstation.png b/packages/woocommerce-germanized-dhl/assets/img/packstation.png new file mode 100755 index 0000000000000000000000000000000000000000..903d8388b38a91c4f425492bcb1c256e4f79068c GIT binary patch literal 6273 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 G6Z#+NBmHjx literal 0 HcmV?d00001 diff --git a/packages/woocommerce-germanized-dhl/assets/img/parcelshop.png b/packages/woocommerce-germanized-dhl/assets/img/parcelshop.png new file mode 100755 index 0000000000000000000000000000000000000000..15fafae42ac6ed518a4586160fb8f0d3d3fefa05 GIT binary patch literal 5538 zcma)=2RNJS`^Tx#(rSw$cBoRVkpw|(5_|7ig4jurSVwVCrBtZBDYbX0S-WbM)@api zjoR9pMe(Dj=bZkobN=JKuJ?VP=gIy3+~XNnk_XzFN>r3glte^CR4U4F-P5<|*?och z^jR=5qr2lJNV{9yq*ZJ!Mbasq#t;GLy7jWx7^3Rrg( zP((mj0K_Rx2?PQq-EHk)x^Tsx^3$Farvo1E3KJCc^70b!5)#0=+Y5rl#l;0d5J3op z|I~sX=Yzo`z4wiH0g5RcFE< zX~G;aI6M+#gHnM@pOOR|9c^JCs2B(g78M4GLQb1tuowg)rzj5+g33XJKnikll7jz` z{#X5fl5Mdz9%vK>|C4NcN){D9nrs3PJ|@-NcA z$&!NqNcG18`(xh!tiwN@g2h1cP>?7BA&d|KgAu}Fa4|1tK9{V5Zs;EqD#vF`d?cwlO# zxnH_cYS&vONJX`Ria6yhkS-+aJ~TcDqdOX)`^@RK!y`(4r+fg$XBzvK_ZqR&Vg$(UlXG-W#COvh(|rf_{b#UJ zSB#yVX^dlAQ%K)(Rd5Gd@=>U(s{`D>^BLy)(+7XIeEHh6xXE{~_xsE4Zsn&0-NI`# zetT1o9`X?FPsXjXN_cit^X6LDTcQtrg7ipVn}v?oVl$Zl0Od~;O}<{=?=ajVc_2HM zaDJVtdFZ|Aa;H<~9-wY-+Lwc9zER3|w_AmtqgZ8N^Fw;%+LOM8%`nFmDz}oZIb-x& z*f{QAiF<0O|;Zk>dNJz12 zEO0Xwie}Qx)wLnaJv=X0@odxyQ)pOh(>%k((dKs-Q%@ifjF*R|A_Ni@xMSsd)t22Y zGu|0PfBG=Pct}&&P05XbEU2_|iaew}60o-Rqfj)J}jA*#>I^M(SWG z$8YsrIeXr{cd6V^z4RJJ@|x($$TZW|1+sgy9byD;hpRUSE61o@CJ68ClhKfHRg{hn zRhx70XSzdYwz$yC3=9luia8(4*$itJMcUk4W7{JLtP(X5F-LluVv4E8UG_QVa6|pB zrwtt!h?=iQM+1Qw8hYt?7DRY)oEeNU>rT1OD@l))5fu?piD38oE7&HF%RGdZz?r(E zVdGj%@WbnuRdj%Pmki5|W^UIQ6z0BQaqEz{9~ydMZ0Arrv4n>;;ox*?=E8?u(4J@7 zn~$?^6$#~Q71|Z6Nc4VeAMuGRu+Hb!3i|K@qkSv>>spmo$JWr8|1iHR%a!5b;jo)r zr6FRGcOQp2JT4j>X-sf_m_ewN)nz*Xx#6nYj+R0~205L4mtVc|*#2 zz;!IE!Qk%QJW{-OO_`+{n_0 zqN5|nwp>;l!N=E+v~s=5&|@3&PIUU4bRFq>UX?Pn_O0094&R7#m3$%MyUwG<6k^F$ z#XxtDof;=sYl*4H1-M((FyaeIRy`(gTRtF2M#qSPiDPDQiA?ZLn(A}w0Ly^c+4B@7 zvL2JqcNA?m$-GHz^seTihbeC8DE40(Q6*5(g}1(-pSCd*5o7f*C##j~Yu(&Be9o}@gk%l?BR%|RCZm{|4bvrySn#(kjJX4&ir7VjQd%1`CEmGtjZvWI zkx_e$1L+*Hdtz^7nl9}v?aQ`cy-$}}NHrxh3M{26;+^X*SQl~d#D3$_L?p%1hY+93 zY#rxUo#CS8En#PGrxN|FJW~9=psnwd4%-?nlmvs)z=cPa3{H`huNz>r*#dLgiHFmD4*vY+fpjPQdN`71hy(~MfMkF zsWWSqJsgouDN00`CRI+|GoV%+6hP2lvI@#Rv@oLZZgP*s`tX(7FZh4HYeNAd4AN=x z4f~%E7}jU@d#|TXsUI4-6hG7R%9Fl2=>L^|Zb+QGu&O~r;=<5Luvq4@KwRs1A*4F? zv7WM=I5!}D$Y$tL{QgWc zN5Q~aSW&1aM@n61wW%3J$(0P!K{Z(v`SH0*Z9w3$0jYWY5V$E<>{{e~6}kwCrRWsc zFnw3e2N+boVYi^UyO}!eToXIuW^%#Rw+kDa&-jY>p8LLHo01)%J#S^EIzYB1VwRn- z9%AG_wYlRj!RqUIeAOz0EI#c`ilz;{o3AP2RV|e1ktGOcQy%lcaF(%c5_GkZL@Kv! ztvmaM`vPlOMUR-hiETCHVgQEH1mdIy>ts%J9UVe$Vt0T&T$9A`|~0xq5NXwYGCq0N*r2M z7hAuzO_%~ClDeTf?Cx_Ezqy;i6%A?O8o;y78c4A2J_aTwdbFw7n@BZMfE4iYCw>Uu zkRGkVPdY@M_h3(o@>z5oKD16Z4Lo|V?&drnHoeaiZU22`%B`vjA;R{65rZyQLyI5d)FtN7b( zw?&%#C;X6&9uV(%4oVkIkuggA$b^p)T~ytp%+#t7&&!l=OTh@2eg>a|>zDKa*fW#r zvSD>=R~Odf`H8#8gwk&*_~eW;3-!;2^7f7h?|cRr!HZ0BvAB4xMuwG%^32^jtMtHSLIYHHvv+APvzCy8h?PD* ziIgWF_z)dP-pMkmmBYjyZsyJ5aJgv~lkwZ9k4m2po+k79)x2?X4)%<968%tlTx3A6 z&E{Sg#+xQ~!1NY99<-BM%aN7N1?;qOB};H@tCDo+2v+c=$=9h_0qE)hK!lvE%N;H< z=UX<(>FtuHv};oKTPqZt-Lh~uCLKHXCCnH@)}kZBo!E=D?6Ed3DQ(0n;GBW@=llk< z_qI&uX4`8acXk#k2$=`NJ9G7xhp_y*$>v=TA-)G4+GwYg5tLmFaL>Jmr^QXC`RMaW zc)-D~ze{zJmELGv0W(!G^NSofl?G3wzerT-$QAAC!HO41s_ryA(uplX$n2viwB0TB zW~9L*Pdh8J;pz}-x|KA$m?u`E3PMc|g+7Ly5!MB_MUk55?<^T4Z1Zj?+J-A^&%4I! zw=#oEiY?yXQlam|aNfG^wny5w`jIO2t5Lwol{!NIgGgS;jeZsDH%L=%f>JM2&$gc2 z#m*H58YP-|e_HfmP66KO%MPC+Rx--{gas|4_Uaf2v)+(qjc|%d^4o%90+9W4?MsegM>%8OBsk4oBnshn z<;%@Bb#(sS0(9c#Hy1_YE-$IUnvo!zH_eZ6d8FJ{wcmXb6UNdc84{9$RGM4nDRys6 z@g#T#Y`qume3G<$8^5$+f*M{0&jA%;#tcoUMhfL;iCGf_=*d3*=B6uB&E&C5@u;Sr zdj5?O_?yyb!Z(_NI?ARm*ZR`6+N~F|t_MXer>QeBl`?b8>4OFd{FI>!BXn+e;ZF;tTaZc=5`)_l`-4oK`M`wY1}uBYbLUA z5w6fKM%rP>^QR?y-NQyjZm*2L7uAvQO3JcJ?s^o~dqLr~3f?Y5X)OC*sT=@9u+jTE z_ZveJ23R7hBi{e{N+oHL_7q8O%if4dxT@~c7pn7{;Whn}bXtiRE=91jGLahDMnzWK zT^-Y;`N}CVZf5v{5yS%E+`L5L8+gd#Dw;)7IwHN%F1k$JM!6+icSCHwud{!Io^*@Y z{SI|u#ChapknHvp(d|K}G=kZt%u5zU0%eN538QPtnzvGNhP?0Pw{zt!BK?{xg^bjS z8nam=mf1c%Ddm)e^aL|NR|&9=U&%vA>N+tGBb=tgmN}{fvX`Z*gL zIS}dsu*>vZLNOh$ISMbPI3OIo7ldvm81ur9E>Tb32H%lC`oarXj{15&$V0ul{sH_t z!OZ^Syon~A3G$mMf*38MpHwDJ*19mQ=@sl0MxD&ttiMJ>KT_1@*0z21dr)k0KZ|-O zk%`QG+gDGfR1}dBUQf^=la^r*jg=lFr}T@EM$5?3^ckbAHhO(i0dnZ`2j+nWe%tF}UW(xr7-Qkqd#5+5DO;-rd=gAyH&LPVv_fdRWLhgJR5ONGM?4ftkE5l9 z%>f3?5lDB%Om9Dq{x1u6d1?T$5?efB+i2PCqGX#I0g2YlQsw&`gby(tR%QJbMo*Jf z@=N2KQ(o<>jb}<6ZT7_4v)5w|9y7nH9ASqJq>mcTDSdeAn{(v^4n+>{A0N2H0oc#d1*vZSjD8HSmfTKyX zR_D-`do2|9;RR_nqZpQ8pL-nEM>{vCCE*h&Wrx9`LcZ34JP{ESCAs^DS=n@f(0)m3 z$9N6Ir|)SYnQVqiCmS-^pIM~YWuVd<>1k=^1#9*Pjk=Au#B@6DY)PbJEs|20xKQlf zwn9&(0^?S**7K7ti4OK_HP@WXs}1^}Yz6p!?)z?s6ctJQV6BBUe+XNAG}HQf>cH&< z*4zYE1D!d&>Tf#Zn#`DMZf(E0_pL5XDqJN??{M%#E;~^R&($U~A8Ld0gF+u^$ zJyKi!LSIjR0`p|tawNUcrsD5tWbkOm>FXZZm@1q zKPoI779g;7%+<~?_)$4Xz5zdS} z1o4jNPW16X1bgoedg}M6hlCeqw<1VV<5H*bTj=4{KIS8i3HR`-*pI7G(zzQa-$~*_ z-)H(5GTci;DE1tYvX0#|w>bUcHZ?dGMU(tS1NnO5@TPf@)Y%j|4-Ek5u~EE73W-Gku_*ymCW?&)e?_2p&+F3=Fz73UbrcQ8TiJk& zX$%rbQyrlW1?vlgKp;Jaw-3q=Yx14W8==8|EEXLFfdmH!s|RbS(-^)Gn2wGP1PX`1 z;c7gD8Z(5-BCyq{O!;pjKXkApCXqp=v&b|mXkC}!MGIu1!Qk~k{~X`*q|mLb{s~28 zey@vHA%sn!LtyGq2!#Uq9h1qjBmJA?Z<$Po5IPBBM`F?f8AK8fF8@0r7TM>2&{==; zHHF{Ncz*xydH>@HuVg(Q+R6%rB{9fBByST2jq=qPI)T9?ttW{F|H$%Z);jTPnJ6-q z$s$mRBy+4jPf49j_C_HPaI6m02m{rDL$#1F7!nRQGC?ABv|&ats0IeB2l<8iU;ckr z_NEa7DI_ZEyRtV=SsMX^X`7g6!J$xX7)%R^L72czjA15F3_=s9WrF*m{1f$GWj)9* zrGEXuzODNYAASvrz(H}^+Heyb0?P}ELtwBtBOC^2g3#8|(ALt@_(%6&>Q6zx#Weqo zOW$O1|Cj7f)L&!|G047TDj@*-Z|LKyK z?bUCM;Oi`}6X*-`m_NFTzOX`0^-f+h!kc4_9Q*`kTwDV#HA?7fd|V6l@aVR7OIOe` zmo_6NZ`Y2Dw9A|^-gn)?0r=E`;#j)vnBny)nY=@eUrwnwCdY#v{Z$MjE=XQ8QwmeM zE^J;lVd5`4&}+`&R#y(UoJfBi>=P^}Gs^C{`Op~M_V)hT+S3Wnq%N~9wQoBmSq&IK z_B_bvD!pjX6SfGSlQB-TKBuHRx&NvrMc$|{A#KZ}>zT|+@Ej87k!P8nA>tVcYfcUc zZqU5?kn96`*I`-d(~r<3Xz+DK!u^)wGJ8BO44R(qG0xhV%9YS+O$`;2KQUSa8y;%n z$L%P;ZRfi)E^fm89s_rJ?#go_2TExCLYl@8U0`+_Gf(i5ayYjLKebyBoS64O0|u5 z1(U0gpR>ML_I6|~-wPNfh5oF7d9rf^|i_OUTTr#t2m$T>^_65&(hP zO@YQ7tSI-HU(bd1ea`BUe=a?~x!G8|_r7il$n-ExnGy?0-{{2W^8_eukdS$eTdgp$ zSFH;sclca9<6VjzdUGPEeSxbIU+eTSuH=xh3dtA^Z3A;JKF{VSR=x&?myu90FWjgy3JW^ASnp)iqzHfQ8!dtck zssSKAZgGhWu^PPzt&7W~Z}DLpd39~#2V^Z)D|l6AUYZ#XQBEstcs;mZqceH$(rUfV zSU~-ft8ljjO9P_CAG}-}a`vF8z~uYn>mL+!f)n%S6X)JR#RsJ9=#KHh=5~mEtl2#I zXX5#_4py=WW(o7UQ`xbiWXD|0gdh$Oy7)%-_2q@Uske==rBQjlS&+aRH!VJ|YJHiA z?8iDbC&kpF5GS;tk9rSj0zh7tU63moBua!RI+xJm+k9 zaUiy{5`FN?yH?vA;IS{O$EVkhY_#?fBdY!du^+4{ft4kf8)n8FhzT@q>4^ChL|_T1 zHeQP%`7~_DR$BB-im;?g1W(i5*qevDC{wQTfSFHrs@&D$FqVyxVeQ3)=%xvYyrb3q zAN%x>QOE!gf7QWThGQGkx)a;n6)O;>r)$UiG&{osJFl2`76Q%W%!t^B&4Yq zfpTy?UB{m?PURQ?u71=zwc;OY(`8EDEgM|)CO<_wVg~^Da4KFr;YFWGM|h!JxiolEwqVu=~Ah1L(F#D>mr#TG5*NfID4dk3;jwqc~W#&K;p)jq{PHHx2*HR%If8s zeArIID}v75NB(Zx=pNE98UI9M5)dwOZt_Fcq-KOLKu~l8!_{8(5!xYWNtqDy%*C@O z>l8+O(&cgZvW-nc0zEKXxd3?$GNft>+FT`DA`&yRA)^wo3DjpirLe1|zc8Y>elSr5 zBm`>(oIbyai*Xi|^AW9kFjAqlt?u%WC3K{ecKC*;#tUs9YR=ZPcJZs$VFMxtV$mT{ zn`#VmP#}b`YUf7V7+Jte^!}6f^xUm>CPGdppNU4@uuS|?oOn~{W%_)?0CFD^*j*+L z5eun0=RH#|D=>K1$~Ih{$fkIz1Biz+6@wlc&o7ObIEys(qizQ29YaU8!S%%@k_H=#ed3 zyS!>Bt#xNy_ixR^>xUscdA;beTUqBe?)vmYw4@RUX?uHXL zOh-6Nji`-IEN*-0>d8Eab7`o#sV!;?7rk2c#`Bi4#YjW=foP!@1=WJP++=*n(bPic zyG5_4UN^XsM)_Q^Q|a61u>h|y5487plv?BmW>@AP-U&-)eFXyS7ujm@Uv{r^i3N1Oy*`d2FjxE^Sc^aE|uz9Uyfim5zv(UW9 z63EVLi7uQ&KmB<7^lXbo)FW?r6=T8zi9m>#40}!k9ScQ@H0dd6P53QQa>DXBTuGs< zQ%<{7vLU$I%`LAlH>y$QcG8X=JM4Ehx1C^*()O=%1kOy_uDq9(l6<=AyY}h!e)#*b zUNn2!eD6J4VZ%w#*q244eKQq;BUqheF@PBwjn2bky<9sK)nzWE)Eap#@@-Lk0&nUQ z*m@u;P;NXq_WAhWA}28D?fo$#@xt0llR@)Z;B@H?zev6vG4G^yOCHmWE~z5nkP8{T zj&{|}EO179%~|-7;`mvH&OWbMsLH0uBWsSX5uF6pVILlcoEYsm zv@C9^n*6R7cC&rL4CkKEE|(ddRA%A8MOjs-+8{CB=mh4yU6WOXw@4;aN337W)uY>*2o0tyangd#v4;K(%RgkC-M% z&a$d3Qd-{`EEh}mu(6R)OuC9!ebFVMw!bp8s(E)P$3E=vQBNXWUdyiIea4HqZux~F zHmis88SmR(37O%qKO3}kkfd#ZHr?6Akv-1(aE5R4%fiF)@y~xxf4)H!B%IQzI&5EWL<#0BJjPUhE!5Qy8@$F zDRuDh@y}gOGN$CaGn6l$VOM9f(FIitWM6`ScJ6qPb;Ub;cDBNyGx~35*X%|PNOzCb zO&*bXaAG)cNaya6?>}OD+iOz+OIGt|{ss(DU|C=|*Sz`+@o)P~6dA8_+ literal 0 HcmV?d00001 diff --git a/packages/woocommerce-germanized-dhl/assets/img/wp-int-eu-preview.png b/packages/woocommerce-germanized-dhl/assets/img/wp-int-eu-preview.png new file mode 100644 index 0000000000000000000000000000000000000000..a4438cd37871b9f9b09dcea86194710b24f235c8 GIT binary patch literal 23720 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 literal 0 HcmV?d00001 diff --git a/packages/woocommerce-germanized-dhl/assets/img/wp-int-preview.png b/packages/woocommerce-germanized-dhl/assets/img/wp-int-preview.png new file mode 100644 index 0000000000000000000000000000000000000000..6ac0f7e34640b1734b84b0e087f8c0f81d10fd1b GIT binary patch literal 49144 zcmV)CK*GO?P)00093P)t-s|NsB} z{{8>}0HUIz%*@OoAtAW9xcvP5yu7^k_xJJg@h>kgl9H18`uZg%B^w(X_4V}9(b0~M zj!jKX78Vxn?(XX9>cPRmot>Spudo0A`h0wRfq{XQm6hP&;Iy=~rlzI}3JToZ+{MMk z`TzfNa&phl&zhQ=<>ci?Mo0ht^kZXVI5#({s;WLdJ`oWS>H7c4$;tBh|Ni;$)YR1C z;^O}G>DSlShlYpp|Nm!aXaD`{i;Iir@%sMo+)`3fcXxPJR#x@u+urj2tgNl@_WEpV zYx3dE`0(cHPiP-s|?++SyuKTW@Y}&$W{J>C(^g{nqLG*~qjV0svrLUeV<6 z+~n-V-|@=2sqX6Hq{ZCg+0oa$ptjlg+{dTO=llQ%N#6SZz18dh4O!~j$J5^CnXk&d z&))(ueMtran8oS<3@Gl_yXeoc=IrpY#@RFj0Kun?%BX;wyV%Rs-LA~*`{~8Lpm>6( z&-&cK0u*fl1U6d;0mHDKsk_j8p2JsjmTj27jiD zCksVjKWlF^FfkruRy9jyL=cLEr*lG1NfJv;H54@oDVef~4;7O_006wRNklPATi{ijh2iU4@6|1dQE7VD=wbkxr ztzFvMsvT;Ftyb*TPTODi9`CyxBq5fn4YszvAKZ7}yt~{#@80*mcL63Gzu~}6sO&!> z960;Hf8<&&NvB(@mP-4Ek8M|*fa5q2HvD!#+*AzC|ke( zc)uCA&@{Q^$i#6iSe;edc-7GTxL{OE)v(Ft`Xsnm z-L<+q2l6)WHMj%dIedJ?{LQ9V&QB zC0~N~;)PcjRH6zERdN<@m_<@Hkx2{j>u@C5yj<+Ms-^+Kp`lmSHV!7u%apF3soxO- zyv8r8nzH!%s=*hG2j;e0B^K+-g$w2+By306mvikOlW?^**-P+VwD6jn=?sV%;Tb?R zBEHC~a!Ng}iF_TKO_TA+ows0P({;GCys~!E*zLG*NG{pB!)qId4XP)2$!svb*V^

>hTl;x^cnSN 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

' . esc_html_x( 'Shipping Provider', 'shipments', 'woocommerce-germanized' ) . '

' . esc_html_x( 'You may find all the available shipping providers as a list here. Click on the link to edit the provider-specific settings.', 'shipments', 'woocommerce-germanized' ) . '

', + 'position' => array( + 'edge' => 'left', + 'align' => 'left', + ), + ), + ), + 'activate' => array( + 'target' => '.wc-gzd-setting-tab-rows tr:first-child .wc-gzd-shipping-provider-activated .woocommerce-gzd-input-toggle-trigger', + 'next' => 'new', + 'next_url' => '', + 'next_trigger' => array(), + 'options' => array( + 'content' => '

' . esc_html_x( 'Activate', 'shipments', 'woocommerce-germanized' ) . '

' . esc_html_x( 'Activate or deactivate a shipping provider by toggling this button.', 'shipments', 'woocommerce-germanized' ) . '

', + 'position' => array( + 'edge' => 'right', + 'align' => 'left', + ), + ), + ), + 'new' => array( + 'target' => 'ul.wc-gzd-settings-breadcrumb .breadcrumb-item-active a.page-title-action:first', + 'next' => '', + 'next_url' => self::get_next_pointers_link(), + 'next_trigger' => array(), + 'options' => array( + 'content' => '

' . esc_html_x( 'Add new', 'shipments', 'woocommerce-germanized' ) . '

' . esc_html_x( 'You may want to manually add a new shipping provider in case an automatic integration does not exist.', 'shipments', 'woocommerce-germanized' ) . '

', + 'position' => array( + 'edge' => 'top', + 'align' => 'top', + ), + ), + ), + ), + ); + } + + return $pointers; + } + + public static function get_description() { + if ( $provider = self::get_current_provider() ) { + return $provider->get_description( 'edit' ); + } + + return ''; + } + + public static function get_breadcrumb( $current_section = '' ) { + $provider = self::get_current_provider(); + + $breadcrumb[] = array( + 'class' => 'tab', + 'href' => $provider ? admin_url( 'admin.php?page=wc-settings&tab=germanized-shipping_provider' ) : '', + 'title' => ! $provider ? self::get_breadcrumb_label( _x( 'Shipping Provider', 'shipments', 'woocommerce-germanized' ) ) : _x( 'Shipping Provider', 'shipments', 'woocommerce-germanized' ), + ); + + if ( $provider = self::get_current_provider() ) { + $breadcrumb[] = array( + 'class' => 'section', + 'href' => ! empty( $current_section ) ? $provider->get_edit_link() : '', + 'title' => ( $provider->get_id() <= 0 && '' === $provider->get_title() ) ? self::get_breadcrumb_label( _x( 'New', 'shipments-shipping-provider', 'woocommerce-germanized' ), $current_section ) : self::get_breadcrumb_label( $provider->get_title(), $current_section ), + ); + } + + if ( ! empty( $current_section ) ) { + $breadcrumb[] = array( + 'class' => 'section', + 'href' => '', + 'title' => self::get_section_title( $current_section ), + ); + } + + return $breadcrumb; + } + + protected static function get_section_title( $section = '' ) { + $sections = self::get_sections(); + $section_label = isset( $sections[ $section ] ) ? $sections[ $section ] : ''; + + return $section_label; + } + + protected static function get_breadcrumb_label( $label, $current_section = '' ) { + $help_link = self::get_help_link(); + $provider = self::get_current_provider(); + + if ( $provider && empty( $current_section ) ) { + if ( ! empty( $help_link ) ) { + $label = $label . '' . _x( 'Learn more', 'shipments', 'woocommerce-germanized' ) . ''; + } + + if ( ! empty( $provider->get_signup_link() ) ) { + $label = $label . '' . _x( 'Not yet a customer?', 'shipments', 'woocommerce-germanized' ) . ''; + } + } elseif ( ! $provider ) { + $label = $label . '' . _x( 'Add provider', 'shipments', 'woocommerce-germanized' ) . ''; + + if ( ! empty( $help_link ) ) { + $label = $label . '' . _x( 'Learn more', 'shipments', 'woocommerce-germanized' ) . ''; + } + } + + return $label; + } + + public static function save( $section = '' ) { + if ( $provider = self::get_current_provider() ) { + $is_new = $provider->get_id() <= 0 ? true : false; + + $provider->update_settings( $section, null, false ); + + if ( $is_new ) { + if ( empty( $provider->get_tracking_desc_placeholder( 'edit' ) ) ) { + $provider->set_tracking_desc_placeholder( $provider->get_default_tracking_desc_placeholder() ); + } + + if ( empty( $provider->get_tracking_url_placeholder( 'edit' ) ) ) { + $provider->set_tracking_url_placeholder( $provider->get_default_tracking_url_placeholder() ); + } + } + + if ( isset( $_GET['provider'] ) && 'new' === $_GET['provider'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + add_filter( 'woocommerce_gzd_shipments_shipping_provider_is_manual_creation_request', '__return_true', 15 ); + } + + $provider->save(); + + if ( isset( $_GET['provider'] ) && 'new' === $_GET['provider'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + remove_filter( 'woocommerce_gzd_shipments_shipping_provider_is_manual_creation_request', '__return_true', 15 ); + } + + if ( $is_new ) { + $url = admin_url( 'admin.php?page=wc-settings&tab=germanized-shipping_provider&provider=' . $provider->get_name() ); + wp_safe_redirect( $url ); + } + } + } + + public static function get_settings( $current_section = '' ) { + if ( $provider = self::get_current_provider() ) { + return $provider->get_settings( $current_section ); + } else { + return array(); + } + } + + public static function output_providers() { + global $hide_save_button; + + $hide_save_button = true; + self::provider_screen(); + } + + protected static function provider_screen() { + $helper = Helper::instance(); + $providers = $helper->get_shipping_providers(); + $providers = apply_filters( 'woocommerce_gzd_shipment_admin_provider_list', $providers ); + + include_once Package::get_path() . '/includes/admin/views/html-settings-provider-list.php'; + } + + public static function get_sections() { + if ( $provider = self::get_current_provider() ) { + return $provider->get_setting_sections(); + } else { + return array(); + } + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Admin/ReturnTable.php b/packages/woocommerce-germanized-shipments/src/Admin/ReturnTable.php new file mode 100644 index 000000000..be9ffee3b --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Admin/ReturnTable.php @@ -0,0 +1,101 @@ +'; + $columns['title'] = _x( 'Title', 'shipments', 'woocommerce-germanized' ); + $columns['date'] = _x( 'Date', 'shipments', 'woocommerce-germanized' ); + $columns['status'] = _x( 'Status', 'shipments', 'woocommerce-germanized' ); + $columns['items'] = _x( 'Items', 'shipments', 'woocommerce-germanized' ); + $columns['sender'] = _x( 'Sender', 'shipments', 'woocommerce-germanized' ); + $columns['weight'] = _x( 'Weight', 'shipments', 'woocommerce-germanized' ); + $columns['dimensions'] = _x( 'Dimensions', 'shipments', 'woocommerce-germanized' ); + $columns['order'] = _x( 'Order', 'shipments', 'woocommerce-germanized' ); + $columns['actions'] = _x( 'Actions', 'shipments', 'woocommerce-germanized' ); + + return $columns; + } + + /** + * @param ReturnShipment $shipment + * @param $actions + * + * @return mixed + */ + protected function get_custom_actions( $shipment, $actions ) { + + if ( isset( $actions['shipped'] ) ) { + unset( $actions['shipped'] ); + } + + if ( ! $shipment->has_status( 'delivered' ) && ! $shipment->has_status( 'requested' ) ) { + $actions['received'] = array( + 'url' => wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_gzd_update_shipment_status&status=delivered&shipment_id=' . $shipment->get_id() ), 'update-shipment-status' ), + 'name' => _x( 'Delivered', 'shipments', 'woocommerce-germanized' ), + 'action' => 'delivered', + ); + } + + if ( $shipment->has_status( 'processing' ) ) { + $actions['email_notification'] = array( + 'url' => wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_gzd_send_return_shipment_notification_email&shipment_id=' . $shipment->get_id() ), 'send-return-shipment-notification' ), + 'name' => _x( 'Send notification to customer', 'shipments', 'woocommerce-germanized' ), + 'action' => 'send-return-notification email', + ); + } + + if ( $shipment->is_customer_requested() && $shipment->has_status( 'requested' ) ) { + $actions['confirm'] = array( + 'url' => wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_gzd_confirm_return_request&shipment_id=' . $shipment->get_id() ), 'confirm-return-request' ), + 'name' => _x( 'Confirm return request', 'shipments', 'woocommerce-germanized' ), + 'action' => 'confirm', + ); + } + + return $actions; + } + + public function get_main_page() { + return 'admin.php?page=wc-gzd-return-shipments'; + } + + protected function get_custom_bulk_actions( $actions ) { + $actions['confirm_requests'] = _x( 'Confirm open return requests', 'shipments', 'woocommerce-germanized' ); + + return $actions; + } + + /** + * Handles the post author column output. + * + * @since 4.3.0 + * + * @param ReturnShipment $shipment The current shipment object. + */ + public function column_sender( $shipment ) { + $address = $shipment->get_formatted_sender_address(); + + if ( $address ) { + echo '' . esc_html( preg_replace( '##i', ', ', $address ) ) . ''; + } else { + echo '–'; + } + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Admin/Settings.php b/packages/woocommerce-germanized-shipments/src/Admin/Settings.php new file mode 100644 index 000000000..adc93da8e --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Admin/Settings.php @@ -0,0 +1,610 @@ + array( + 'menu' => array( + 'target' => '.wc-gzd-settings-breadcrumb .page-title-action:last', + 'next' => 'default', + 'next_url' => '', + 'next_trigger' => array(), + 'options' => array( + 'content' => '

' . esc_html_x( 'Manage shipments', 'shipments', 'woocommerce-germanized' ) . '

' . esc_html_x( 'To view all your existing shipments in a list you might follow this link or click on the shipments link within the WooCommerce sub-menu.', 'shipments', 'woocommerce-germanized' ) . '

', + 'position' => array( + 'edge' => 'left', + 'align' => 'left', + ), + ), + ), + 'default' => array( + 'target' => '#woocommerce_gzd_shipments_notify_enable-toggle', + 'next' => 'auto', + 'next_url' => '', + 'next_trigger' => array(), + 'options' => array( + 'content' => '

' . esc_html_x( 'E-Mail Notification', 'shipments', 'woocommerce-germanized' ) . '

' . esc_html_x( 'By enabling this option customers receive an email notification as soon as a shipment is marked as shipped.', 'shipments', 'woocommerce-germanized' ) . '

', + 'position' => array( + 'edge' => 'left', + 'align' => 'left', + ), + ), + ), + 'auto' => array( + 'target' => '#woocommerce_gzd_shipments_auto_enable-toggle', + 'next' => 'returns', + 'next_url' => '', + 'next_trigger' => array(), + 'options' => array( + 'content' => '

' . esc_html_x( 'Automation', 'shipments', 'woocommerce-germanized' ) . '

' . esc_html_x( 'Decide whether you want to automatically create shipments to orders reaching a specific status. You can always adjust your shipments by manually editing the shipment within the edit order screen.', 'shipments', 'woocommerce-germanized' ) . '

', + 'position' => array( + 'edge' => 'left', + 'align' => 'left', + ), + ), + ), + 'returns' => array( + 'target' => '#shipments_return_options-description', + 'next' => '', + 'next_url' => $next_url, + 'next_trigger' => array(), + 'options' => array( + 'content' => '

' . esc_html_x( 'Returns', 'shipments', 'woocommerce-germanized' ) . '

' . sprintf( _x( 'Germanized can help you to minimize manual work while handling customer returns. Learn more about returns within our %s.', 'shipments', 'woocommerce-germanized' ), '' . _x( 'documentation', 'shipments', 'woocommerce-germanized' ) . '' ) . '

', + 'position' => array( + 'edge' => 'top', + 'align' => 'top', + ), + ), + ), + ), + ); + } + + return $pointers; + } + + protected static function get_general_settings() { + + $statuses = array_diff_key( wc_gzd_get_shipment_statuses(), array_flip( array( 'gzd-requested' ) ) ); + + $settings = array( + array( + 'title' => '', + 'type' => 'title', + 'id' => 'shipments_options', + ), + + array( + 'title' => _x( 'Notify', 'shipments', 'woocommerce-germanized' ), + 'desc' => _x( 'Notify customers about new shipments.', 'shipments', 'woocommerce-germanized' ) . '
' . sprintf( _x( 'Notify customers by email as soon as a shipment is marked as shipped. %s the notification email.', 'shipments', 'woocommerce-germanized' ), '' . _x( 'Manage', 'shipments notification', 'woocommerce-germanized' ) . '' ) . '
', + 'id' => 'woocommerce_gzd_shipments_notify_enable', + 'default' => 'yes', + 'type' => 'gzd_toggle', + ), + + array( + 'title' => _x( 'Default provider', 'shipments', 'woocommerce-germanized' ), + 'desc_tip' => _x( 'Select a default shipping provider which will be selected by default in case no provider could be determined automatically.', 'shipments', 'woocommerce-germanized' ), + 'id' => 'woocommerce_gzd_shipments_default_shipping_provider', + 'default' => '', + 'type' => 'select', + 'options' => wc_gzd_get_shipping_provider_select(), + 'class' => 'wc-enhanced-select', + ), + + array( + 'type' => 'sectionend', + 'id' => 'shipments_options', + ), + + array( + 'title' => _x( 'Automation', 'shipments', 'woocommerce-germanized' ), + 'type' => 'title', + 'id' => 'shipments_auto_options', + ), + + array( + 'title' => _x( 'Enable', 'shipments', 'woocommerce-germanized' ), + 'desc' => _x( 'Automatically create shipments for orders.', 'shipments', 'woocommerce-germanized' ), + 'id' => 'woocommerce_gzd_shipments_auto_enable', + 'default' => 'yes', + 'type' => 'gzd_toggle', + ), + + array( + 'title' => _x( 'Order statuses', 'shipments', 'woocommerce-germanized' ), + 'desc_tip' => _x( 'Create shipments as soon as the order reaches one of the following status(es).', 'shipments', 'woocommerce-germanized' ), + 'id' => 'woocommerce_gzd_shipments_auto_statuses', + 'default' => array( 'wc-processing', 'wc-on-hold' ), + 'class' => 'wc-enhanced-select-nostd', + 'options' => wc_get_order_statuses(), + 'type' => 'multiselect', + 'custom_attributes' => array( + 'data-show_if_woocommerce_gzd_shipments_auto_enable' => '', + 'data-placeholder' => _x( 'On new order creation', 'shipments', 'woocommerce-germanized' ), + ), + ), + + array( + 'title' => _x( 'Default status', 'shipments', 'woocommerce-germanized' ), + 'desc_tip' => _x( 'Choose a default status for the automatically created shipment.', 'shipments', 'woocommerce-germanized' ), + 'id' => 'woocommerce_gzd_shipments_auto_default_status', + 'default' => 'gzd-processing', + 'class' => 'wc-enhanced-select', + 'options' => $statuses, + 'type' => 'select', + 'custom_attributes' => array( + 'data-show_if_woocommerce_gzd_shipments_auto_enable' => '', + ), + ), + + array( + 'title' => _x( 'Update status', 'shipments', 'woocommerce-germanized' ), + 'desc' => _x( 'Mark order as completed after order is fully shipped.', 'shipments', 'woocommerce-germanized' ) . '
' . _x( 'This option will automatically update the order status to completed as soon as all required shipments have been marked as shipped.', 'shipments', 'woocommerce-germanized' ) . '
', + 'id' => 'woocommerce_gzd_shipments_auto_order_shipped_completed_enable', + 'default' => 'yes', + 'type' => 'gzd_toggle', + ), + + array( + 'title' => _x( 'Mark as shipped', 'shipments', 'woocommerce-germanized' ), + 'desc' => _x( 'Mark shipments as shipped after order completion.', 'shipments', 'woocommerce-germanized' ) . '
' . _x( 'This option will automatically update contained shipments to shipped (if possible, e.g. not yet delivered) as soon as the order was marked as completed.', 'shipments', 'woocommerce-germanized' ) . '
', + 'id' => 'woocommerce_gzd_shipments_auto_order_completed_shipped_enable', + 'default' => 'no', + 'type' => 'gzd_toggle', + ), + + array( + 'type' => 'sectionend', + 'id' => 'shipments_auto_options', + ), + + array( + 'title' => _x( 'Returns', 'shipments', 'woocommerce-germanized' ), + 'type' => 'title', + 'id' => 'shipments_return_options', + 'desc' => sprintf( _x( 'Returns can be added manually by the shop manager or by the customer. Decide what suits you best by turning customer-added returns on or off in your %s.', 'shipments', 'woocommerce-germanized' ), '' . _x( 'shipping provider settings', 'shipments', 'woocommerce-germanized' ) . '' ), + ), + + array( + 'type' => 'shipment_return_reasons', + ), + + array( + 'title' => _x( 'Days to return', 'shipments', 'woocommerce-germanized' ), + 'desc' => '
' . sprintf( _x( 'In case one of your %s supports returns added by customers you might want to limit the number of days a customer is allowed to add returns to an order. The days are counted starting with the date the order was shipped, completed or created (by checking for existance in this order).', 'shipments', 'woocommerce-germanized' ), '' . _x( 'shipping providers', 'shipments', 'woocommerce-germanized' ) . '' ) . '
', + 'css' => 'max-width: 60px;', + 'type' => 'number', + 'id' => 'woocommerce_gzd_shipments_customer_return_open_days', + 'default' => '14', + ), + + array( + 'type' => 'sectionend', + 'id' => 'shipments_return_options', + ), + + array( + 'title' => _x( 'Customer Account', 'shipments', 'woocommerce-germanized' ), + 'type' => 'title', + 'id' => 'shipments_customer_options', + ), + + array( + 'title' => _x( 'List', 'shipments', 'woocommerce-germanized' ), + 'desc' => _x( 'List shipments on customer account order screen.', 'shipments', 'woocommerce-germanized' ), + 'id' => 'woocommerce_gzd_shipments_customer_account_enable', + 'default' => 'yes', + 'type' => 'gzd_toggle', + ), + + array( + 'type' => 'sectionend', + 'id' => 'shipments_customer_options', + ), + ); + + return $settings; + } + + public static function get_address_label_by_prop( $prop, $type = 'shipper' ) { + $label = ''; + $fields = wc_gzd_get_shipment_setting_default_address_fields( $type ); + + if ( array_key_exists( $prop, $fields ) ) { + $label = $fields[ $prop ]; + } + + return $label; + } + + protected static function get_address_field_type_by_prop( $prop ) { + $type = 'text'; + + if ( 'country' === $prop ) { + $type = 'single_select_country'; + } + + return $type; + } + + protected static function get_address_desc_by_prop( $prop ) { + $desc = false; + + if ( 'customs_reference_number' === $prop ) { + $desc = _x( 'Your customs reference number, e.g. EORI number', 'shipments', 'woocommerce-germanized' ); + } + + return $desc; + } + + protected static function get_address_fields_to_skip() { + return array( 'state', 'street', 'street_number', 'full_name' ); + } + + protected static function get_address_settings() { + $shipper_fields = wc_gzd_get_shipment_setting_address_fields( 'shipper' ); + $return_fields = wc_gzd_get_shipment_setting_address_fields( 'return' ); + + $settings = array( + array( + 'title' => _x( 'Shipper Address', 'shipments', 'woocommerce-germanized' ), + 'type' => 'title', + 'id' => 'shipments_shipper_address', + ), + ); + + // Use WooCommerce address data as fallback/default data on install + $default_shipper_address_data = array( + 'company' => get_option( 'name' ), + 'address_1' => get_option( 'woocommerce_store_address' ), + 'address_2' => get_option( 'woocommerce_store_address_2' ), + 'city' => get_option( 'woocommerce_store_city' ), + 'postcode' => get_option( 'woocommerce_store_postcode' ), + 'email' => get_option( 'woocommerce_email_from_address' ), + 'country' => get_option( 'woocommerce_default_country' ), + ); + + foreach ( $shipper_fields as $field => $value ) { + if ( in_array( $field, self::get_address_fields_to_skip(), true ) ) { + continue; + } + + $default_value = ''; + + if ( array_key_exists( $field, $default_shipper_address_data ) ) { + $default_value = $default_shipper_address_data[ $field ]; + } + + $settings = array_merge( + $settings, + array( + array( + 'title' => self::get_address_label_by_prop( $field ), + 'type' => self::get_address_field_type_by_prop( $field ), + 'id' => "woocommerce_gzd_shipments_shipper_address_{$field}", + 'default' => $default_value, + 'desc_tip' => self::get_address_desc_by_prop( $field ), + ), + ) + ); + } + + $settings = array_merge( + $settings, + array( + array( + 'type' => 'sectionend', + 'id' => 'shipments_shipper_address', + ), + + array( + 'title' => _x( 'Return Address', 'shipments', 'woocommerce-germanized' ), + 'type' => 'title', + 'id' => 'shipments_return_address', + ), + ) + ); + + foreach ( $return_fields as $field => $value ) { + if ( in_array( $field, self::get_address_fields_to_skip(), true ) ) { + continue; + } + + $settings = array_merge( + $settings, + array( + array( + 'title' => self::get_address_label_by_prop( $field ), + 'type' => self::get_address_field_type_by_prop( $field ), + 'id' => "woocommerce_gzd_shipments_return_address_{$field}", + 'default' => '', + 'placeholder' => $value, + 'desc_tip' => self::get_address_desc_by_prop( $field ), + ), + ) + ); + } + + $settings = array_merge( + $settings, + array( + array( + 'type' => 'sectionend', + 'id' => 'shipments_return_address', + ), + ) + ); + + return $settings; + } + + protected static function get_packaging_settings() { + $settings = array( + array( + 'title' => '', + 'type' => 'title', + 'id' => 'packaging_options', + ), + + array( + 'type' => 'packaging_list', + ), + + array( + 'title' => _x( 'Default packaging', 'shipments', 'woocommerce-germanized' ), + 'desc_tip' => _x( 'Choose a packaging which serves as fallback or default in case no suitable packaging could be matched for a certain shipment.', 'shipments', 'woocommerce-germanized' ), + 'id' => 'woocommerce_gzd_shipments_default_packaging', + 'default' => '', + 'type' => 'select', + 'options' => wc_gzd_get_packaging_select(), + 'class' => 'wc-enhanced-select', + ), + + array( + 'type' => 'packaging_reports', + 'title' => _x( 'Packaging Report', 'shipments', 'woocommerce-germanized' ), + 'id' => 'packaging_reports', + ), + + array( + 'type' => 'sectionend', + 'id' => 'packaging_options', + ), + ); + + return $settings; + } + + public static function get_settings( $current_section = '' ) { + $settings = array(); + + if ( '' === $current_section ) { + $settings = self::get_general_settings(); + } elseif ( 'packaging' === $current_section ) { + $settings = self::get_packaging_settings(); + } elseif ( 'address' === $current_section ) { + $settings = self::get_address_settings(); + } + + return $settings; + } + + public static function get_additional_breadcrumb_items( $breadcrumb ) { + return $breadcrumb; + } + + public static function get_sections() { + return array( + '' => _x( 'General', 'shipments', 'woocommerce-germanized' ), + 'packaging' => _x( 'Packaging', 'shipments', 'woocommerce-germanized' ), + 'address' => _x( 'Addresses', 'shipments', 'woocommerce-germanized' ), + ); + } + + public static function after_save( $current_section = '' ) { + if ( 'packaging' === $current_section ) { + if ( isset( $_POST['save'] ) && 'create_report' === wc_clean( wp_unslash( $_POST['save'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing + $start_date = isset( $_POST['report_year'] ) ? wc_clean( wp_unslash( $_POST['report_year'] ) ) : '01-01-' . ( (int) date( 'Y' ) - 1 ); // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.DateTime.RestrictedFunctions.date_date + $start_date = ReportHelper::string_to_datetime( $start_date ); + + ReportQueue::start( 'yearly', $start_date ); + } + } + } + + public static function get_sanitized_settings( $settings, $data = null ) { + if ( is_null( $data ) ) { + $data = $_POST; // phpcs:ignore WordPress.Security.NonceVerification.Missing + } + + if ( empty( $data ) ) { + return false; + } + + $settings_to_save = array(); + + // Loop options and get values to save. + foreach ( $settings as $option ) { + + if ( ! isset( $option['id'] ) || empty( $option['id'] ) || ! isset( $option['type'] ) || in_array( $option['type'], array( 'title', 'sectionend' ), true ) || ( isset( $option['is_option'] ) && false === $option['is_option'] ) ) { + continue; + } + + $option_key = $option['id']; + $raw_value = isset( $data[ $option_key ] ) ? wp_unslash( $data[ $option_key ] ) : null; + + // Format the value based on option type. + switch ( $option['type'] ) { + case 'checkbox': + $value = '1' === $raw_value || 'yes' === $raw_value ? 'yes' : 'no'; + break; + case 'textarea': + $value = wp_kses_post( trim( $raw_value ) ); + break; + case 'password': + $value = is_null( $raw_value ) ? '' : addslashes( $raw_value ); + $value = trim( $value ); + + if ( class_exists( 'WC_GZD_Secret_Box_Helper' ) ) { + $encrypted = \WC_GZD_Secret_Box_Helper::encrypt( $value ); + + if ( ! is_wp_error( $encrypted ) ) { + $value = $encrypted; + } + } + break; + case 'multiselect': + case 'multi_select_countries': + $value = array_filter( array_map( 'wc_clean', (array) $raw_value ) ); + break; + case 'image_width': + $value = array(); + if ( isset( $raw_value['width'] ) ) { + $value['width'] = wc_clean( $raw_value['width'] ); + $value['height'] = wc_clean( $raw_value['height'] ); + $value['crop'] = isset( $raw_value['crop'] ) ? 1 : 0; + } else { + $value['width'] = $option['default']['width']; + $value['height'] = $option['default']['height']; + $value['crop'] = $option['default']['crop']; + } + break; + case 'select': + $allowed_values = empty( $option['options'] ) ? array() : array_map( 'strval', array_keys( $option['options'] ) ); + if ( empty( $option['default'] ) && empty( $allowed_values ) ) { + $value = null; + break; + } + $default = ( empty( $option['default'] ) ? $allowed_values[0] : $option['default'] ); + $value = in_array( $raw_value, $allowed_values, true ) ? $raw_value : $default; + break; + case 'relative_date_selector': + $value = wc_parse_relative_date_option( $raw_value ); + break; + default: + $value = wc_clean( $raw_value ); + break; + } + + /** + * Sanitize the value of an option. + * + * @since 2.4.0 + */ + $value = apply_filters( 'woocommerce_admin_settings_sanitize_option', $value, $option, $raw_value ); + + $settings_to_save[ $option_key ] = $value; + } + + return $settings_to_save; + } + + public static function render_label_fields( $settings, $shipment, $echo = false ) { + $missing_div_closes = 0; + ob_start(); + foreach ( $settings as $setting ) { + $setting = wp_parse_args( + $setting, + array( + 'id' => '', + 'type' => 'text', + 'custom_attributes' => array(), + ) + ); + + if ( has_action( "woocommerce_gzd_shipment_label_admin_field_{$setting['id']}" ) ) { + do_action( "woocommerce_gzd_shipment_label_admin_field_{$setting['id']}", $setting, $shipment ); + } elseif ( 'select' === $setting['type'] ) { + woocommerce_wp_select( $setting ); + } elseif ( 'multiselect' === $setting['type'] ) { + $setting['class'] = 'select short wc-enhanced-select'; + $setting['custom_attributes'] = array_merge( $setting['custom_attributes'], array( 'multiple' => 'multiple' ) ); + + if ( ! strstr( $setting['id'], '[]' ) ) { + $setting['name'] = $setting['id'] . '[]'; + } + + woocommerce_wp_select( $setting ); + } elseif ( 'checkbox' === $setting['type'] ) { + woocommerce_wp_checkbox( $setting ); + } elseif ( 'textarea' === $setting['type'] ) { + woocommerce_wp_textarea_input( $setting ); + } elseif ( 'text' === $setting['type'] ) { + woocommerce_wp_text_input( $setting ); + } elseif ( 'date' === $setting['type'] ) { + $setting['class'] = 'datepicker'; + $setting['type'] = 'date'; + + woocommerce_wp_text_input( $setting ); + } elseif ( 'number' === $setting['type'] ) { + woocommerce_wp_text_input( $setting ); + } elseif ( 'services_start' === $setting['type'] ) { + $hide_default = isset( $setting['hide_default'] ) ? wc_string_to_bool( $setting['hide_default'] ) : false; + $missing_div_closes++; + ?> +

+ + + + + + +

+
+ +
+ +
+ +
+ 0 ) { + while ( $missing_div_closes > 0 ) { + $missing_div_closes--; + echo '
'; + } + } + + $html = ob_get_clean(); + + if ( ! $echo ) { + return $html; + } else { + echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + } + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Admin/Table.php b/packages/woocommerce-germanized-shipments/src/Admin/Table.php new file mode 100644 index 000000000..1c756864d --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Admin/Table.php @@ -0,0 +1,1168 @@ + 'simple', + ) + ); + + $this->shipment_type = $args['type']; + + parent::__construct( + array( + 'plural' => 'shipments', + 'screen' => isset( $args['screen'] ) ? $args['screen'] : null, + ) + ); + } + + public function set_default_hidden_columns( $columns, $screen ) { + if ( $this->screen->id === $screen->id ) { + $columns = array_merge( $columns, $this->get_default_hidden_columns() ); + } + + return $columns; + } + + protected function get_default_hidden_columns() { + return array( + 'weight', + 'dimensions', + 'packaging', + ); + } + + public function enable_query_removing( $args ) { + $args = array_merge( + $args, + array( + 'changed', + 'bulk_action', + ) + ); + + return $args; + } + + /** + * Handle bulk actions. + * + * @param string $redirect_to URL to redirect to. + * @param string $action Action name. + * @param array $ids List of ids. + * @return string + */ + public function handle_bulk_actions( $action, $ids, $redirect_to ) { + $ids = array_reverse( array_map( 'absint', $ids ) ); + $changed = 0; + + if ( false !== strpos( $action, 'mark_' ) ) { + + $shipment_statuses = wc_gzd_get_shipment_statuses(); + $new_status = substr( $action, 5 ); // Get the status name from action. + + // Sanity check: bail out if this is actually not a status, or is not a registered status. + if ( isset( $shipment_statuses[ 'gzd-' . $new_status ] ) ) { + + foreach ( $ids as $id ) { + + if ( $shipment = wc_gzd_get_shipment( $id ) ) { + $shipment->update_status( $new_status, true ); + + /** + * Action that fires after a shipment bulk status update has been processed. + * + * @param integer $shipment_id The shipment id. + * @param string $new_status The new shipment status. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_shipment_edit_status', $id, $new_status ); + $changed++; + } + } + } + } elseif ( 'delete' === $action ) { + foreach ( $ids as $id ) { + if ( $shipment = wc_gzd_get_shipment( $id ) ) { + $shipment->delete( true ); + $changed++; + } + } + } elseif ( 'confirm_requests' === $action ) { + foreach ( $ids as $id ) { + if ( $shipment = wc_gzd_get_shipment( $id ) ) { + if ( 'return' === $shipment->get_type() ) { + if ( $shipment->is_customer_requested() && $shipment->has_status( 'requested' ) ) { + if ( $shipment->confirm_customer_request() ) { + $changed++; + } + } + } + } + } + } + + /** + * Filter to decide whether a Shipment has changed during bulk action or not. + * + * @param boolean $changed Whether the Shipment has changed or not. + * @param string $action The bulk action + * @param string $redirect_to The redirect URL. + * @param Table $table The table instance. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + $changed = apply_filters( 'woocommerce_gzd_shipments_bulk_action', $changed, $action, $ids, $redirect_to, $this ); + + if ( $changed ) { + $redirect_to = add_query_arg( + array( + 'changed' => $changed, + 'ids' => join( ',', $ids ), + 'bulk_action' => $action, + ), + $redirect_to + ); + } + + return esc_url_raw( $redirect_to ); + } + + public function output_notice() { + + if ( ! empty( $this->notice ) ) { + $type = isset( $this->notice['type'] ) ? $this->notice['type'] : 'success'; + + echo '
' . wp_kses_post( wpautop( $this->notice['message'] ) ) . '
'; + } + + $this->notice = array(); + } + + /** + * Show confirmation message that order status changed for number of orders. + */ + public function set_bulk_notice() { + + $number = isset( $_REQUEST['changed'] ) ? absint( $_REQUEST['changed'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $bulk_action = isset( $_REQUEST['bulk_action'] ) ? wc_clean( wp_unslash( $_REQUEST['bulk_action'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended + + if ( 'delete' === $bulk_action ) { + + $this->set_notice( sprintf( _nx( '%d shipment deleted.', '%d shipments deleted.', $number, 'shipments', 'woocommerce-germanized' ), number_format_i18n( $number ) ) ); + + } elseif ( strpos( $bulk_action, 'mark_' ) !== false ) { + + $shipment_statuses = wc_gzd_get_shipment_statuses(); + + // Check if any status changes happened. + foreach ( $shipment_statuses as $slug => $name ) { + + if ( 'mark_' . str_replace( 'gzd-', '', $slug ) === $bulk_action ) { // WPCS: input var ok, CSRF ok. + $this->set_notice( sprintf( _nx( '%d shipment status changed.', '%d shipment statuses changed.', $number, 'shipments', 'woocommerce-germanized' ), number_format_i18n( $number ) ) ); + break; + } + } + } + + /** + * Action that fires after bulk updating shipments. Action might be usefull to add + * custom notices after custom bulk actions have been applied. + * + * The dynamic portion of this hook, `$this->get_hook_prefix()` is used to construct a + * unique hook for a shipment type e.g. return. In case of simple shipments the type is omitted. + * + * Example hook name: woocommerce_gzd_return_shipments_table_bulk_notice + * + * @param string $bulk_action The bulk action. + * @param Table $shipment_table The table object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( "{$this->get_hook_prefix()}bulk_notice", $bulk_action, $this ); + } + + public function set_notice( $message, $type = 'success' ) { + $this->notice = array( + 'message' => $message, + 'type' => $type, + ); + } + + protected function get_stati() { + return $this->stati; + } + + /** + * @return bool + */ + public function ajax_user_can() { + return current_user_can( 'edit_shop_orders' ); + } + + public function get_page_option() { + return 'woocommerce_page_wc_gzd_shipments_per_page'; + } + + /** + * @global array $avail_post_stati + * @global WP_Query $wp_query + * @global int $per_page + * @global string $mode + */ + public function prepare_items() { + global $per_page; + + $per_page = $this->get_items_per_page( $this->get_page_option(), 10 ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited + + /** + * Filter to adjust Shipment's table items per page. + * + * The dynamic portion of this hook, `$this->get_hook_prefix()` is used to construct a + * unique hook for a shipment type e.g. return. In case of simple shipments the type is omitted. + * + * Example hook name: woocommerce_gzd_return_shipments_table_edit_per_page + * + * @param integer $per_page Number of Shipments per page. + * @param string $type The type in this case shipment. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + $per_page = apply_filters( "{$this->get_hook_prefix()}edit_per_page", $per_page, 'shipment' ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited + $this->stati = wc_gzd_get_shipment_statuses(); + $this->counts = wc_gzd_get_shipment_counts( $this->shipment_type ); + $paged = $this->get_pagenum(); + + $args = array( + 'limit' => $per_page, + 'paginate' => true, + 'offset' => ( $paged - 1 ) * $per_page, + 'count_total' => true, + 'type' => $this->shipment_type, + ); + + if ( isset( $_REQUEST['shipment_status'] ) && in_array( $_REQUEST['shipment_status'], array_keys( $this->stati ), true ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $args['status'] = wc_clean( wp_unslash( $_REQUEST['shipment_status'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended + } + + if ( isset( $_REQUEST['orderby'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + if ( 'weight' === $_REQUEST['orderby'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $args['orderby'] = 'weight'; + } else { + $args['orderby'] = wc_clean( wp_unslash( $_REQUEST['orderby'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended + } + } + + if ( isset( $_REQUEST['order'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $args['order'] = 'asc' === $_REQUEST['order'] ? 'ASC' : 'DESC'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended + } + + if ( isset( $_REQUEST['parent_id'] ) && ! empty( $_REQUEST['parent_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $args['parent_id'] = absint( $_REQUEST['parent_id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended + } + + if ( isset( $_REQUEST['order_id'] ) && ! empty( $_REQUEST['order_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $args['order_id'] = absint( $_REQUEST['order_id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended + } + + if ( isset( $_REQUEST['m'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $m = wc_clean( wp_unslash( $_REQUEST['m'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $year = substr( $m, 0, 4 ); + + if ( ! empty( $year ) ) { + $month = ''; + $day = ''; + + if ( strlen( $m ) > 5 ) { + $month = substr( $m, 4, 2 ); + } + + if ( strlen( $m ) > 7 ) { + $day = substr( $m, 6, 2 ); + } + + $datetime = new WC_DateTime(); + $datetime->setDate( $year, 1, 1 ); + + if ( ! empty( $month ) ) { + $datetime->setDate( $year, $month, 1 ); + } + + if ( ! empty( $day ) ) { + $datetime->setDate( $year, $month, $day ); + } + + $next_month = clone $datetime; + $next_month->modify( '+ 1 month' ); + // Make sure to not include next month first day + $next_month->modify( '-1 day' ); + + $args['date_created'] = $datetime->format( 'Y-m-d' ) . '...' . $next_month->format( 'Y-m-d' ); + } + } + + if ( isset( $_REQUEST['s'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $search = wc_clean( wp_unslash( $_REQUEST['s'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended + + if ( ! is_numeric( $search ) ) { + $search = '*' . $search . '*'; + } + + $args['search'] = $search; + } + + // Query the user IDs for this page + $this->query = new ShipmentQuery( apply_filters( "{$this->get_hook_prefix()}query_args", $args, $this ) ); + $this->items = $this->query->get_shipments(); + + $this->set_pagination_args( + array( + 'total_items' => $this->query->get_total(), + 'per_page' => $per_page, + ) + ); + } + + /** + */ + public function no_items() { + echo esc_html_x( 'No shipments found', 'shipments', 'woocommerce-germanized' ); + } + + /** + * Determine if the current view is the "All" view. + * + * @since 4.2.0 + * + * @return bool Whether the current view is the "All" view. + */ + protected function is_base_request() { + $vars = $_GET; // phpcs:ignore WordPress.Security.NonceVerification.Recommended + unset( $vars['paged'] ); + + if ( empty( $vars ) ) { + return true; + } + + return 1 === count( $vars ); + } + + /** + * @global array $locked_post_status This seems to be deprecated. + * @global array $avail_post_stati + * @return array + */ + protected function get_views() { + + $status_links = array(); + $num_shipments = $this->counts; + $total_shipments = array_sum( (array) $num_shipments ); + $class = ''; + $all_args = array(); + + if ( empty( $class ) && ( $this->is_base_request() || isset( $_REQUEST['all_shipments'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $class = 'current'; + } + + $all_inner_html = sprintf( + _nx( + 'All (%s)', + 'All (%s)', + $total_shipments, + 'shipments', + 'woocommerce-germanized-shipments' + ), + number_format_i18n( $total_shipments ) + ); + + $status_links['all'] = $this->get_edit_link( $all_args, $all_inner_html, $class ); + + foreach ( wc_gzd_get_shipment_statuses() as $status => $title ) { + $class = ''; + + if ( ! in_array( $status, array_keys( $this->stati ), true ) || empty( $num_shipments[ $status ] ) ) { + continue; + } + + if ( isset( $_REQUEST['shipment_status'] ) && $status === $_REQUEST['shipment_status'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $class = 'current'; + } + + $status_args = array( + 'shipment_status' => $status, + ); + + $status_label = sprintf( + translate_nooped_plural( _nx_noop( ( $title . ' (%s)' ), ( $title . ' (%s)' ), 'shipments', 'woocommerce-germanized' ), $num_shipments[ $status ] ), // phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralSingle,WordPress.WP.I18n.NonSingularStringLiteralPlural + number_format_i18n( $num_shipments[ $status ] ) + ); + + $status_links[ $status ] = $this->get_edit_link( $status_args, $status_label, $class ); + } + + return $status_links; + } + + /** + * Helper to create links to edit.php with params. + * + * @since 4.4.0 + * + * @param string[] $args Associative array of URL parameters for the link. + * @param string $label Link text. + * @param string $class Optional. Class attribute. Default empty string. + * @return string The formatted link string. + */ + protected function get_edit_link( $args, $label, $class = '' ) { + $url = add_query_arg( $args, $this->get_main_page() ); + + $class_html = $aria_current = ''; + if ( ! empty( $class ) ) { + $class_html = sprintf( + ' class="%s"', + esc_attr( $class ) + ); + + if ( 'current' === $class ) { + $aria_current = ' aria-current="page"'; + } + } + + return sprintf( + '%s', + esc_url( $url ), + $class_html, + $aria_current, + $label + ); + } + + /** + * @return string + */ + public function current_action() { + if ( isset( $_REQUEST['delete_all'] ) || isset( $_REQUEST['delete_all2'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + return 'delete_all'; + } + + return parent::current_action(); + } + + /** + * Display a monthly dropdown for filtering items + * + * @since 3.0.6 + * + * @global wpdb $wpdb + * @global WP_Locale $wp_locale + * + * @param string $post_type + */ + protected function months_dropdown( $type ) { + global $wpdb, $wp_locale; + + $extra_checks = "AND shipment_status != 'auto-draft'"; + + if ( isset( $_GET['shipment_status'] ) && 'all' !== $_GET['shipment_status'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $extra_checks = $wpdb->prepare( ' AND shipment_status = %s', wc_clean( wp_unslash( $_GET['shipment_status'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended + } + + $months = $wpdb->get_results( "SELECT DISTINCT YEAR( shipment_date_created ) AS year, MONTH( shipment_date_created ) AS month FROM $wpdb->gzd_shipments WHERE 1=1 $extra_checks ORDER BY shipment_date_created DESC" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared + $month_count = count( $months ); + + if ( ! $month_count || ( 1 === $month_count && 0 === $months[0]->month ) ) { + return; + } + + $m = isset( $_GET['m'] ) ? absint( wp_unslash( $_GET['m'] ) ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended + ?> + + + +
+

+
+ +
+ get_notices( 'error' ); + $success = $handler->get_notices( 'success' ); + ?> + + +
+

+
+ + + admin_after_error(); ?> + +
+

get_success_message() ); ?>

+
+ + + admin_handled(); + /** + * Action that fires after a certain bulk action result has been rendered. + * + * The dynamic portion of this hook, `$this->get_hook_prefix()` is used to construct a + * unique hook for a shipment type e.g. return. In case of simple shipments the type is omitted. + * `$bulk_action` refers to the bulk action handled. + * + * Example hook name: woocommerce_gzd_return_shipments_table_mark_processing_handled + * + * @param BulkActionHandler $bulk_action_handler The bulk action handler. + * @param string $bulk_action The bulk action. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( "{$this->get_hook_prefix()}bulk_action_{$bulk_action}_handled", $handler, $bulk_action ); + ?> + + reset(); ?> + + +
+ months_dropdown( 'shipment' ); + $this->order_filter(); + + /** + * Action that fires after outputting Shipments table view filters. + * Might be used to add custom filters to the Shipments table view. + * + * The dynamic portion of this hook, `$this->get_hook_prefix()` is used to construct a + * unique hook for a shipment type e.g. return. In case of simple shipments the type is omitted. + * + * Example hook name: woocommerce_gzd_return_shipments_table_filters + * + * @param string $which top or bottom. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( "{$this->get_hook_prefix()}filters", $which ); + + $output = ob_get_clean(); + + if ( ! empty( $output ) ) { + echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + + submit_button( _x( 'Filter', 'shipments', 'woocommerce-germanized' ), '', 'filter_action', false, array( 'id' => 'shipment-query-submit' ) ); + } + } + ?> +
+ + + '; + $columns['title'] = _x( 'Title', 'shipments', 'woocommerce-germanized' ); + $columns['date'] = _x( 'Date', 'shipments', 'woocommerce-germanized' ); + $columns['status'] = _x( 'Status', 'shipments', 'woocommerce-germanized' ); + $columns['items'] = _x( 'Items', 'shipments', 'woocommerce-germanized' ); + $columns['address'] = _x( 'Address', 'shipments', 'woocommerce-germanized' ); + $columns['packaging'] = _x( 'Packaging', 'shipments', 'woocommerce-germanized' ); + $columns['weight'] = _x( 'Weight', 'shipments', 'woocommerce-germanized' ); + $columns['dimensions'] = _x( 'Dimensions', 'shipments', 'woocommerce-germanized' ); + $columns['order'] = _x( 'Order', 'shipments', 'woocommerce-germanized' ); + $columns['actions'] = _x( 'Actions', 'shipments', 'woocommerce-germanized' ); + + return $columns; + } + + /** + * @return array + */ + public function get_columns() { + $columns = $this->get_custom_columns(); + + /** + * Filters the columns displayed in the Shipments list table. + * + * The dynamic portion of this hook, `$this->get_hook_prefix()` is used to construct a + * unique hook for a shipment type e.g. return. In case of simple shipments the type is omitted. + * + * Example hook name: woocommerce_gzd_return_shipments_table_edit_per_page + * + * @param string[] $columns An associative array of column headings. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + $columns = apply_filters( "{$this->get_hook_prefix()}columns", $columns ); + + return $columns; + } + + /** + * @return array + */ + protected function get_sortable_columns() { + return apply_filters( + "{$this->get_hook_prefix()}sortable_columns", + array( + 'date' => array( 'date_created', false ), + 'weight' => 'weight', + 'order' => 'order_id', + ), + $this + ); + } + + /** + * Gets the name of the default primary column. + * + * @since 4.3.0 + * + * @return string Name of the default primary column, in this case, 'title'. + */ + protected function get_default_primary_column_name() { + return 'title'; + } + + /** + * Handles the default column output. + * + * @since 4.3.0 + * + * @param Shipment $shipment The current shipment object. + * @param string $column_name The current column name. + */ + public function column_default( $shipment, $column_name ) { + + /** + * Fires in each custom column in the Shipments list table. + * + * The dynamic portion of this hook, `$this->get_hook_prefix()` is used to construct a + * unique hook for a shipment type e.g. return. In case of simple shipments the type is omitted. + * + * Example hook name: woocommerce_gzd_return_shipments_table_filters + * + * @param string $column_name The name of the column to display. + * @param integer $shipment_id The current shipment id. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( "{$this->get_hook_prefix()}custom_column", $column_name, $shipment->get_id() ); + } + + public function get_main_page() { + return 'admin.php?page=wc-gzd-shipments'; + } + + /** + * Handles the post author column output. + * + * @since 4.3.0 + * + * @param Shipment $shipment The current shipment object. + */ + public function column_title( $shipment ) { + $title = sprintf( _x( '%1$s #%2$s', 'shipment title', 'woocommerce-germanized' ), wc_gzd_get_shipment_label_title( $shipment->get_type() ), $shipment->get_id() ); + + if ( $order = $shipment->get_order() ) { + echo '' . wp_kses_post( $title ) . ' '; + } else { + echo wp_kses_post( $title ) . ' '; + } + + echo '

'; + + if ( $packaging = $shipment->get_packaging() ) { + echo '' . wp_kses_post( $packaging->get_description() ) . ' '; + } + + $provider = $shipment->get_shipping_provider(); + + if ( ! empty( $provider ) ) { + echo '' . sprintf( esc_html_x( 'via %s', 'shipments', 'woocommerce-germanized' ), wp_kses_post( wc_gzd_get_shipping_provider_title( $provider ) ) ) . ' '; + } + + if ( $tracking_id = $shipment->get_tracking_id() ) { + if ( $shipment->has_tracking() && ( $tracking_url = $shipment->get_tracking_url() ) ) { + echo '' . esc_html( $tracking_id ) . ''; + } else { + echo '' . esc_html( $tracking_id ) . ''; + } + } + + echo '

'; + } + + protected function get_custom_actions( $shipment, $actions ) { + return $actions; + } + + /** + * Handles shipment actions. + * + * @since 0.0.1 + * + * @param Shipment $shipment The current shipment object. + */ + protected function column_actions( $shipment ) { + echo '

'; + + /** + * Action that fires before table actions are outputted for a Shipment. + * + * The dynamic portion of this hook, `$this->get_hook_prefix()` is used to construct a + * unique hook for a shipment type e.g. return. In case of simple shipments the type is omitted. + * + * Example hook name: woocommerce_gzd_return_shipments_table_actions_start + * + * @param Shipment $shipment The shipment object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( "{$this->get_hook_prefix()}actions_start", $shipment ); + + $actions = array(); + + if ( $shipment->has_status( array( 'draft' ) ) ) { + $actions['processing'] = array( + 'url' => wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_gzd_update_shipment_status&status=processing&shipment_id=' . $shipment->get_id() ), 'update-shipment-status' ), + 'name' => _x( 'Processing', 'shipments', 'woocommerce-germanized' ), + 'action' => 'processing', + ); + } + + if ( $shipment->has_status( array( 'draft', 'processing' ) ) ) { + $actions['shipped'] = array( + 'url' => wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_gzd_update_shipment_status&status=shipped&shipment_id=' . $shipment->get_id() ), 'update-shipment-status' ), + 'name' => _x( 'Shipped', 'shipments', 'woocommerce-germanized' ), + 'action' => 'shipped', + ); + } + + if ( $shipment->supports_label() ) { + + if ( $label = $shipment->get_label() ) { + + $actions['download_label'] = array( + 'url' => $label->get_download_url(), + 'name' => _x( 'Download label', 'shipments', 'woocommerce-germanized' ), + 'action' => 'download-label download', + 'target' => '_blank', + ); + + } elseif ( $shipment->needs_label() ) { + + $actions['generate_label'] = array( + 'url' => '#', + 'name' => _x( 'Generate label', 'shipments', 'woocommerce-germanized' ), + 'action' => 'generate-label generate', + ); + + include Package::get_path() . '/includes/admin/views/label/html-shipment-label-backbone.php'; + } + } + + $actions = $this->get_custom_actions( $shipment, $actions ); + + /** + * Filters the actions available for Shipments table list column. + * + * The dynamic portion of this hook, `$this->get_hook_prefix()` is used to construct a + * unique hook for a shipment type e.g. return. In case of simple shipments the type is omitted. + * + * Example hook name: woocommerce_gzd_return_shipments_table_actions + * + * @param array $actions The registered Shipment actions. + * @param Shipment $shipment The shipment object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + $actions = apply_filters( "{$this->get_hook_prefix()}actions", $actions, $shipment ); + + echo wc_gzd_render_shipment_action_buttons( $actions ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + + /** + * Action that fires after table actions are outputted for a Shipment. + * + * The dynamic portion of this hook, `$this->get_hook_prefix()` is used to construct a + * unique hook for a shipment type e.g. return. In case of simple shipments the type is omitted. + * + * Example hook name: woocommerce_gzd_return_shipments_table_actions_end + * + * @param Shipment $shipment The shipment object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( "{$this->get_hook_prefix()}actions_end", $shipment ); + + echo '

'; + } + + public function column_cb( $shipment ) { + if ( current_user_can( 'edit_shop_orders' ) ) : + ?> + + + + + + get_items() as $item ) : ?> + + + + + + +
+ get_product() ) : ?> + get_name() ); ?> + + get_name() ); ?> + + + get_sku() ? '
' . esc_html_x( 'SKU:', 'shipments', 'woocommerce-germanized' ) . ' ' . esc_html( $item->get_sku() ) . '' : '' ); ?> + + get_hook_prefix()}item_after_name", $item->get_id(), $item, $shipment ); + ?> +
+ get_quantity() ); ?>x +
+ get_formatted_address(); + + if ( $address ) { + echo '' . esc_html( preg_replace( '##i', ', ', $address ) ) . ''; + } else { + echo '–'; + } + } + + /** + * Handles the post author column output. + * + * @since 4.3.0 + * + * @param Shipment $shipment The current shipment object. + */ + public function column_status( $shipment ) { + echo '' . esc_html( wc_gzd_get_shipment_status_name( $shipment->get_status() ) ) . ''; + } + + /** + * Handles the post author column output. + * + * @since 4.3.0 + * + * @param Shipment $shipment The current shipment object. + */ + public function column_weight( $shipment ) { + echo wc_gzd_format_shipment_weight( $shipment->get_total_weight(), $shipment->get_weight_unit() ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + } + + /** + * Handles the post author column output. + * + * @since 4.3.0 + * + * @param Shipment $shipment The current shipment object. + */ + public function column_packaging( $shipment ) { + if ( $packaging = $shipment->get_packaging() ) { + echo wp_kses_post( $packaging->get_description() ); + } else { + echo '–'; + } + } + + /** + * Handles the post author column output. + * + * @since 4.3.0 + * + * @param Shipment $shipment The current shipment object. + */ + public function column_dimensions( $shipment ) { + echo wc_gzd_format_shipment_dimensions( $shipment->get_dimensions(), $shipment->get_dimension_unit() ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + } + + /** + * Handles the post author column output. + * + * @since 4.3.0 + * + * @param Shipment $shipment The current shipment object. + */ + public function column_date( $shipment ) { + $shipment_timestamp = $shipment->get_date_created() ? $shipment->get_date_created()->getTimestamp() : ''; + + if ( ! $shipment_timestamp ) { + echo '–'; + return; + } + + // Check if the order was created within the last 24 hours, and not in the future. + if ( $shipment_timestamp > strtotime( '-1 day', time() ) && $shipment_timestamp <= time() ) { + $show_date = sprintf( + /* translators: %s: human-readable time difference */ + _x( '%s ago', '%s = human-readable time difference', 'woocommerce-germanized' ), + human_time_diff( $shipment->get_date_created()->getTimestamp(), time() ) + ); + } else { + /** + * Filter to adjust the Shipment date format in table view. + * + * @param string $format The date format. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + $show_date = $shipment->get_date_created()->date_i18n( apply_filters( 'woocommerce_gzd_admin_shipment_date_format', _x( 'M j, Y', 'shipments', 'woocommerce-germanized' ) ) ); + } + + printf( + '', + esc_attr( $shipment->get_date_created()->date( 'c' ) ), + esc_html( $shipment->get_date_created()->date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) ) ), + esc_html( $show_date ) + ); + } + + /** + * Handles the post author column output. + * + * @since 4.3.0 + * + * @param Shipment $shipment The current shipment object. + */ + public function column_order( $shipment ) { + if ( ( $order = $shipment->get_order() ) && is_callable( array( $order, 'get_edit_order_url' ) ) ) { + echo '' . esc_html( $order->get_order_number() ) . ''; + } else { + echo esc_html( $shipment->get_order_id() ); + } + } + + /** + * + * @param int|WC_GZD_Shipment $shipment + */ + public function single_row( $shipment ) { + $GLOBALS['shipment'] = $shipment; + $classes = 'shipment shipment-status-' . $shipment->get_status(); + ?> + + single_row_columns( $shipment ); ?> + + shipment_type ? '' : '_' . $this->shipment_type ); + + return "woocommerce_gzd{$suffix}_shipments_table_"; + } + + /** + * @return array + */ + protected function get_bulk_actions() { + $actions = array(); + + if ( current_user_can( 'delete_shop_orders' ) ) { + $actions['delete'] = _x( 'Delete Permanently', 'shipments', 'woocommerce-germanized' ); + } + + $actions['mark_processing'] = _x( 'Change status to processing', 'shipments', 'woocommerce-germanized' ); + $actions['mark_shipped'] = _x( 'Change status to shipped', 'shipments', 'woocommerce-germanized' ); + $actions['mark_delivered'] = _x( 'Change status to delivered', 'shipments', 'woocommerce-germanized' ); + $actions['labels'] = _x( 'Generate and download labels', 'shipments', 'woocommerce-germanized' ); + + $actions = $this->get_custom_bulk_actions( $actions ); + + /** + * Filter to register addtional bulk actions for shipments. + * + * The dynamic portion of this hook, `$this->get_hook_prefix()` is used to construct a + * unique hook for a shipment type e.g. return. In case of simple shipments the type is omitted. + * + * Example hook name: woocommerce_gzd_return_shipments_table_bulk_actions + * + * @param array $actions Array containing key => value pairs. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( "{$this->get_hook_prefix()}bulk_actions", $actions ); + } + +} diff --git a/packages/woocommerce-germanized-shipments/src/Ajax.php b/packages/woocommerce-germanized-shipments/src/Ajax.php new file mode 100644 index 000000000..235a68061 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Ajax.php @@ -0,0 +1,1476 @@ +hide_errors(); + } + + public static function send_return_shipment_notification_email() { + $success = false; + + if ( current_user_can( 'edit_shop_orders' ) && isset( $_REQUEST['shipment_id'] ) ) { + + if ( isset( $_GET['shipment_id'] ) ) { + $referrer = check_admin_referer( 'send-return-shipment-notification' ); + } else { + $referrer = check_ajax_referer( 'send-return-shipment-notification', 'security' ); + } + + if ( $referrer ) { + $shipment_id = absint( wp_unslash( $_REQUEST['shipment_id'] ) ); + + if ( $shipment = wc_gzd_get_shipment( $shipment_id ) ) { + + if ( 'return' === $shipment->get_type() ) { + WC()->mailer()->emails['WC_GZD_Email_Customer_Return_Shipment']->trigger( $shipment_id ); + $success = true; + } + } + } + + if ( isset( $_GET['shipment_id'] ) ) { + wp_safe_redirect( wp_get_referer() ? wp_get_referer() : admin_url( 'admin.php?page=wc-gzd-return-shipments' ) ); + exit; + } else { + if ( $success ) { + wp_send_json( + array( + 'success' => true, + 'messages' => array( + _x( 'Notification successfully sent to customer.', 'shipments', 'woocommerce-germanized' ), + ), + ) + ); + } else { + wp_send_json( + array( + 'success' => false, + 'messages' => array( + _x( 'There was an error while sending the notification.', 'shipments', 'woocommerce-germanized' ), + ), + ) + ); + } + } + } + } + + public static function confirm_return_request() { + $success = false; + + if ( current_user_can( 'edit_shop_orders' ) && isset( $_REQUEST['shipment_id'] ) ) { + + if ( isset( $_GET['shipment_id'] ) ) { + $referrer = check_admin_referer( 'confirm-return-request' ); + } else { + $referrer = check_ajax_referer( 'confirm-return-request', 'security' ); + } + + if ( $referrer ) { + $shipment_id = absint( wp_unslash( $_REQUEST['shipment_id'] ) ); + + if ( $shipment = wc_gzd_get_shipment( $shipment_id ) ) { + if ( 'return' === $shipment->get_type() ) { + + if ( $shipment->confirm_customer_request() ) { + $success = true; + } + } + } + } + + if ( isset( $_GET['shipment_id'] ) ) { + wp_safe_redirect( wp_get_referer() ? wp_get_referer() : admin_url( 'admin.php?page=wc-gzd-return-shipments' ) ); + exit; + } else { + if ( $success ) { + wp_send_json( + array( + 'success' => true, + 'messages' => array( + _x( 'Return request confirmed successfully.', 'shipments', 'woocommerce-germanized' ), + ), + 'shipment_id' => $shipment->get_id(), + 'needs_refresh' => true, + 'fragments' => array( + 'div#shipment-' . $shipment_id => self::get_shipment_html( $shipment ), + ), + ) + ); + } else { + wp_send_json( + array( + 'success' => false, + 'messages' => array( + _x( 'There was an error while confirming the request.', 'shipments', 'woocommerce-germanized' ), + ), + ) + ); + } + } + } + } + + public static function create_shipment_label_form() { + check_ajax_referer( 'create-shipment-label-form', 'security' ); + + if ( ! current_user_can( 'edit_shop_orders' ) || ! isset( $_POST['shipment_id'] ) ) { + wp_die( -1 ); + } + + $shipment_id = absint( $_POST['shipment_id'] ); + $response = array(); + $response_error = array( + 'success' => false, + 'messages' => array( + _x( 'There was an error creating the label.', 'shipments', 'woocommerce-germanized' ), + ), + ); + + if ( ! $shipment = wc_gzd_get_shipment( $shipment_id ) ) { + wp_send_json( $response_error ); + } + + if ( $shipment->supports_label() && $shipment->needs_label() ) { + $html = $shipment->get_label_settings_html(); + } + + $response = array( + 'fragments' => array( + '.wc-gzd-shipment-create-label' => '
' . $html . '
', + ), + 'shipment_id' => $shipment_id, + 'success' => true, + ); + + wp_send_json( $response ); + } + + public static function remove_shipment_label() { + check_ajax_referer( 'remove-shipment-label', 'security' ); + + if ( ! current_user_can( 'edit_shop_orders' ) || ! isset( $_POST['shipment_id'] ) ) { + wp_die( -1 ); + } + + $response = array(); + $response_error = array( + 'success' => false, + 'messages' => array( + _x( 'There was an error deleting the label.', 'shipments', 'woocommerce-germanized' ), + ), + ); + + $shipment_id = absint( $_POST['shipment_id'] ); + + if ( ! $shipment = wc_gzd_get_shipment( $shipment_id ) ) { + wp_send_json( $response_error ); + } + + if ( ! $label = $shipment->get_label() ) { + wp_send_json( $response_error ); + } + + if ( $shipment->delete_label( true ) ) { + $response = array( + 'success' => true, + 'shipment_id' => $shipment->get_id(), + 'needs_refresh' => true, + 'fragments' => array( + 'div#shipment-' . $shipment_id => self::get_shipment_html( $shipment ), + ), + ); + } else { + wp_send_json( $response_error ); + } + + wp_send_json( $response ); + } + + public static function create_shipment_label() { + check_ajax_referer( 'create-shipment-label', 'security' ); + + if ( ! current_user_can( 'edit_shop_orders' ) || ! isset( $_POST['shipment_id'] ) ) { + wp_die( -1 ); + } + + $response = array(); + $response_error = array( + 'success' => false, + 'messages' => array( + _x( 'There was an error processing the label.', 'shipments', 'woocommerce-germanized' ), + ), + ); + + $shipment_id = absint( $_POST['shipment_id'] ); + $result = false; + + if ( ! $shipment = wc_gzd_get_shipment( $shipment_id ) ) { + wp_send_json( $response_error ); + } + + if ( $shipment->supports_label() && $shipment->needs_label() ) { + $data = array(); + + foreach ( $_POST as $key => $value ) { + if ( in_array( $key, array( 'action', 'security' ), true ) ) { + continue; + } + + $data[ $key ] = wc_clean( wp_unslash( $value ) ); + } + + $result = $shipment->create_label( $data ); + } + + if ( is_wp_error( $result ) ) { + $response = array( + 'success' => false, + 'messages' => $result->get_error_messages(), + ); + } elseif ( $label = $shipment->get_label() ) { + + $order_shipment = wc_gzd_get_shipment_order( $shipment->get_order() ); + $order_status_html = $order_shipment ? self::get_global_order_status_html( $order_shipment->get_order() ) : array(); + + $response = array( + 'success' => true, + 'label_id' => $label->get_id(), + 'shipment_id' => $shipment_id, + 'needs_refresh' => true, + 'fragments' => array( + 'div#shipment-' . $shipment_id => self::get_shipment_html( $shipment ), + '.order-shipping-status' => $order_shipment ? self::get_order_status_html( $order_shipment ) : '', + '.order-return-status' => $order_shipment ? self::get_order_return_status_html( $order_shipment ) : '', + '.order_data_column p.wc-order-status' => ! empty( $order_status_html ) ? $order_status_html['status'] : '', + 'input[name=post_status]' => ! empty( $order_status_html ) ? $order_status_html['input'] : '', + 'tr#shipment-' . $shipment_id . ' td.actions .wc-gzd-shipment-action-button-generate-label' => self::label_download_button_html( $label ), + ), + ); + + if ( empty( $response['fragments']['.order_data_column p.wc-order-status'] ) ) { + unset( $response['fragments']['.order_data_column p.wc-order-status'] ); + } + } else { + $response = $response_error; + } + + wp_send_json( $response ); + } + + protected static function get_shipment_html( $p_shipment, $p_is_active = true ) { + $is_active = $p_is_active; + $shipment = $p_shipment; + + ob_start(); + include Package::get_path() . '/includes/admin/views/html-order-shipment.php'; + $html = ob_get_clean(); + + return $html; + } + + protected static function get_label_html( $p_shipment, $p_label = false ) { + $shipment = $p_shipment; + + if ( $p_label ) { + $label = $p_label; + } + + ob_start(); + include Package::get_path() . '/includes/admin/views/label/html-shipment-label.php'; + $html = ob_get_clean(); + + return $html; + } + + /** + * @param ShipmentLabel $label + * + * @return string + */ + protected static function label_download_button_html( $label ) { + return '' . _x( 'Download label', 'shipments', 'woocommerce-germanized' ) . ''; + } + + public static function edit_shipping_provider_status() { + check_ajax_referer( 'edit-shipping-providers', 'security' ); + + if ( ! current_user_can( 'edit_shop_orders' ) || ! isset( $_POST['provider'] ) || ! isset( $_POST['enable'] ) ) { + wp_die( -1 ); + } + + $response_error = array( + 'success' => false, + 'message' => _x( 'There was an error while trying to save the shipping provider status.', 'shipments', 'woocommerce-germanized' ), + ); + + $provider = sanitize_key( wc_clean( wp_unslash( $_POST['provider'] ) ) ); + $enable = wc_clean( wp_unslash( $_POST['enable'] ) ); + $helper = Helper::instance(); + $response = array( + 'success' => true, + 'provider' => $provider, + 'message' => '', + ); + + $helper->load_shipping_providers(); + + if ( $shipping_provider = $helper->get_shipping_provider( $provider ) ) { + if ( 'yes' === $enable ) { + $response['activated'] = 'yes'; + $shipping_provider->activate(); + } else { + $response['activated'] = 'no'; + $shipping_provider->deactivate(); + } + + wp_send_json( $response ); + } else { + wp_send_json( $response_error ); + } + } + + public static function remove_shipping_provider() { + check_ajax_referer( 'remove-shipping-provider', 'security' ); + + if ( ! current_user_can( 'edit_shop_orders' ) || ! isset( $_POST['provider'] ) ) { + wp_die( -1 ); + } + + $response_error = array( + 'success' => false, + 'message' => _x( 'There was an error while trying to delete the shipping provider.', 'shipments', 'woocommerce-germanized' ), + ); + + $provider = sanitize_key( wc_clean( wp_unslash( $_POST['provider'] ) ) ); + $helper = Helper::instance(); + $response = array( + 'success' => true, + 'provider' => $provider, + 'message' => '', + ); + + $helper->load_shipping_providers(); + + if ( $shipping_provider = $helper->get_shipping_provider( $provider ) ) { + $shipping_provider->delete(); + wp_send_json( $response ); + } else { + wp_send_json( $response_error ); + } + } + + public static function shipments_bulk_action_handle() { + $action = isset( $_POST['bulk_action'] ) ? wc_clean( wp_unslash( $_POST['bulk_action'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing + $type = isset( $_POST['type'] ) ? wc_clean( wp_unslash( $_POST['type'] ) ) : 'simple'; // phpcs:ignore WordPress.Security.NonceVerification.Missing + + check_ajax_referer( "woocommerce_gzd_shipments_{$action}", 'security' ); + + if ( ! current_user_can( 'edit_shop_orders' ) || ! isset( $_POST['step'] ) || ! isset( $_POST['ids'] ) ) { + wp_die( -1 ); + } + + $response_error = array( + 'success' => false, + 'message' => _x( 'There was an error while bulk processing shipments.', 'shipments', 'woocommerce-germanized' ), + ); + + $response = array( + 'success' => true, + 'message' => '', + ); + + $handlers = Admin::get_bulk_action_handlers(); + + if ( ! array_key_exists( $action, $handlers ) ) { + wp_send_json( $response_error ); + } + + $ids = isset( $_POST['ids'] ) ? array_map( 'absint', $_POST['ids'] ) : array(); + $step = isset( $_POST['step'] ) ? absint( $_POST['step'] ) : 1; + + $handler = $handlers[ $action ]; + + if ( 1 === $step ) { + $handler->reset( true ); + } + + $handler->set_step( $step ); + $handler->set_ids( $ids ); + $handler->set_shipment_type( $type ); + + $handler->handle(); + + if ( $handler->get_percent_complete() >= 100 ) { + $errors = $handler->get_notices( 'error' ); + + if ( empty( $errors ) ) { + $handler->add_notice( $handler->get_success_message(), 'success' ); + $handler->update_notices(); + } + + wp_send_json_success( + array( + 'step' => 'done', + 'percentage' => 100, + 'url' => $handler->get_success_redirect_url(), + 'type' => $handler->get_shipment_type(), + ) + ); + } else { + wp_send_json_success( + array( + 'step' => ++$step, + 'percentage' => $handler->get_percent_complete(), + 'ids' => $handler->get_ids(), + 'type' => $handler->get_shipment_type(), + ) + ); + } + } + + /** + * @param Order $order + */ + private static function refresh_shipments( &$order ) { + MetaBox::refresh_shipments( $order ); + } + + /** + * @param Order $order + * @param bool $shipment + */ + private static function refresh_shipment_items( &$order, &$shipment = false ) { + MetaBox::refresh_shipment_items( $order, $shipment ); + } + + /** + * @param Order $order + */ + private static function refresh_status( &$order ) { + MetaBox::refresh_status( $order ); + } + + public static function update_shipment_status() { + if ( current_user_can( 'edit_shop_orders' ) && check_admin_referer( 'update-shipment-status' ) && isset( $_GET['status'], $_GET['shipment_id'] ) ) { + $status = sanitize_text_field( wp_unslash( $_GET['status'] ) ); + $shipment = wc_gzd_get_shipment( absint( wp_unslash( $_GET['shipment_id'] ) ) ); + + if ( wc_gzd_is_shipment_status( 'gzd-' . $status ) && $shipment ) { + $shipment->update_status( $status, true ); + /** + * Action to indicate Shipment status change via WP Admin. + * + * @param integer $shipment_id The shipment id. + * @param string $status The status to be switched to. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_updated_shipment_status', $shipment->get_id(), $status ); + } + } + + wp_safe_redirect( wp_get_referer() ? wp_get_referer() : admin_url( 'admin.php?page=wc-gzd-shipments' ) ); + exit; + } + + private static function get_shipment_ids( $shipments ) { + return array_values( + array_map( + function( $s ) { + return $s->get_id(); + }, + $shipments + ) + ); + } + + public static function remove_shipment() { + check_ajax_referer( 'edit-shipments', 'security' ); + + if ( ! current_user_can( 'edit_shop_orders' ) || ! isset( $_POST['shipment_id'] ) ) { + wp_die( -1 ); + } + + $response_error = array( + 'success' => false, + 'message' => _x( 'There was an error processing the shipment', 'shipments', 'woocommerce-germanized' ), + ); + + $response = array( + 'success' => true, + 'message' => '', + ); + + $shipment_id = absint( $_POST['shipment_id'] ); + + if ( ! $shipment = wc_gzd_get_shipment( $shipment_id ) ) { + wp_send_json( $response_error ); + } + + if ( ! $order_shipment = wc_gzd_get_shipment_order( $shipment->get_order() ) ) { + wp_send_json( $response_error ); + } + + $shipment_ids = self::get_shipment_ids( $order_shipment->get_shipments() ); + + if ( $shipment->delete( true ) ) { + $order_shipment->remove_shipment( $shipment_id ); + + if ( 'return' === $shipment->get_type() ) { + $order_shipment->validate_shipments(); + } + + /* + * Check which shipments have been deleted (e.g. multiple in case a return has been removed) + */ + $shipments_removed = array_values( array_diff( $shipment_ids, self::get_shipment_ids( $order_shipment->get_shipments() ) ) ); + $response['shipment_id'] = $shipments_removed; + + $response['fragments'] = array( + '.order-shipping-status' => self::get_order_status_html( $order_shipment ), + '.order-return-status' => self::get_order_return_status_html( $order_shipment ), + ); + + self::send_json_success( $response, $order_shipment ); + } else { + wp_send_json( $response_error ); + } + } + + public static function add_shipment() { + check_ajax_referer( 'edit-shipments', 'security' ); + + if ( ! current_user_can( 'edit_shop_orders' ) || ! isset( $_POST['order_id'] ) ) { + wp_die( -1 ); + } + + $response_error = array( + 'success' => false, + 'message' => _x( 'There was an error while adding the shipment', 'shipments', 'woocommerce-germanized' ), + ); + + $response = array( + 'success' => true, + 'message' => '', + ); + + $order_id = absint( $_POST['order_id'] ); + + if ( ! $order = wc_get_order( $order_id ) ) { + wp_send_json( $response_error ); + } + + if ( ! $order_shipment = wc_gzd_get_shipment_order( $order ) ) { + wp_send_json( $response_error ); + } + + self::refresh_shipment_items( $order_shipment ); + + if ( ! $order_shipment->needs_shipping() ) { + $response_error['message'] = _x( 'This order contains enough shipments already.', 'shipments', 'woocommerce-germanized' ); + wp_send_json( $response_error ); + } + + $shipment = wc_gzd_create_shipment( $order_shipment ); + + if ( is_wp_error( $shipment ) ) { + wp_send_json( $response_error ); + } + + $order_shipment->add_shipment( $shipment ); + + // Mark as active + $is_active = true; + + ob_start(); + include Package::get_path() . '/includes/admin/views/html-order-shipment.php'; + $html = ob_get_clean(); + + $response['new_shipment'] = $html; + $response['new_shipment_type'] = $shipment->get_type(); + $response['fragments'] = array( + '.order-shipping-status' => self::get_order_status_html( $order_shipment ), + '.order-return-status' => self::get_order_return_status_html( $order_shipment ), + ); + + self::send_json_success( $response, $order_shipment ); + } + + public static function add_return_shipment() { + check_ajax_referer( 'edit-shipments', 'security' ); + + if ( ! current_user_can( 'edit_shop_orders' ) || ! isset( $_POST['order_id'] ) ) { + wp_die( -1 ); + } + + $response_error = array( + 'success' => false, + 'message' => _x( 'There was an error processing the shipment', 'shipments', 'woocommerce-germanized' ), + ); + + $response = array( + 'success' => true, + 'message' => '', + 'new_shipment' => '', + ); + + $order_id = absint( $_POST['order_id'] ); + $items = isset( $_POST['return_item'] ) ? (array) wc_clean( wp_unslash( $_POST['return_item'] ) ) : array(); + + if ( ! $order_shipment = wc_gzd_get_shipment_order( $order_id ) ) { + wp_send_json( $response_error ); + } + + self::refresh_shipment_items( $order_shipment ); + + if ( ! $order_shipment->needs_return() ) { + $response_error['message'] = _x( 'This order contains enough returns already.', 'shipments', 'woocommerce-germanized' ); + wp_send_json( $response_error ); + } + + $shipment = wc_gzd_create_return_shipment( $order_shipment, array( 'items' => $items ) ); + + if ( is_wp_error( $shipment ) ) { + wp_send_json( $response_error ); + } + + $order_shipment->add_shipment( $shipment ); + + // Mark as active + $is_active = true; + + ob_start(); + include Package::get_path() . '/includes/admin/views/html-order-shipment.php'; + $html = ob_get_clean(); + + $response['new_shipment'] = $html; + $response['new_shipment_type'] = $shipment->get_type(); + $response['fragments'] = array( + '.order-shipping-status' => self::get_order_status_html( $order_shipment ), + '.order-return-status' => self::get_order_return_status_html( $order_shipment ), + ); + + self::send_json_success( $response, $order_shipment ); + } + + public static function validate_shipment_item_quantities() { + check_ajax_referer( 'edit-shipments', 'security' ); + + if ( ! current_user_can( 'edit_shop_orders' ) || ! isset( $_POST['order_id'] ) ) { + wp_die( -1 ); + } + + $response_error = array( + 'success' => false, + 'message' => _x( 'There was an error processing the shipment', 'shipments', 'woocommerce-germanized' ), + ); + + $response = array( + 'success' => true, + 'message' => '', + ); + + $order_id = absint( $_POST['order_id'] ); + $active = isset( $_POST['active'] ) ? absint( $_POST['active'] ) : 0; + + if ( ! $order = wc_get_order( $order_id ) ) { + wp_send_json( $response_error ); + } + + if ( ! $order_shipment = wc_gzd_get_shipment_order( $order ) ) { + wp_send_json( $response_error ); + } + + static::refresh_shipments( $order_shipment ); + + $order_shipment->validate_shipments(); + + $response['fragments'] = self::get_shipments_html( $order_shipment, $active ); + + self::send_json_success( $response, $order_shipment ); + } + + public static function sync_shipment_items() { + check_ajax_referer( 'edit-shipments', 'security' ); + + if ( ! current_user_can( 'edit_shop_orders' ) || ! isset( $_POST['shipment_id'] ) ) { + wp_die( -1 ); + } + + $response_error = array( + 'success' => false, + 'message' => _x( 'There was an error processing the shipment', 'shipments', 'woocommerce-germanized' ), + ); + + $response = array( + 'success' => true, + 'message' => '', + ); + + $shipment_id = absint( $_POST['shipment_id'] ); + + if ( ! $shipment = wc_gzd_get_shipment( $shipment_id ) ) { + wp_send_json( $response_error ); + } + + if ( ! $order = $shipment->get_order() ) { + wp_send_json( $response_error ); + } + + if ( ! $order_shipment = wc_gzd_get_shipment_order( $order ) ) { + wp_send_json( $response_error ); + } + + $shipment = $order_shipment->get_shipment( $shipment_id ); + + static::refresh_shipment_items( $order_shipment ); + + if ( $shipment->is_editable() ) { + $shipment = $order_shipment->get_shipment( $shipment_id ); + + // Make sure we are working based on the current instance. + $shipment->set_order_shipment( $order_shipment ); + $shipment->sync_items(); + $shipment->save(); + } + + ob_start(); + foreach ( $shipment->get_items() as $item ) { + include Package::get_path() . '/includes/admin/views/html-order-shipment-item.php'; + } + $html = ob_get_clean(); + + $response['fragments'] = array( + '#shipment-' . $shipment->get_id() . ' .shipment-item-list:first' => '
' . $html . '
', + '#shipment-' . $shipment->get_id() . ' .item-count:first' => self::get_item_count_html( $shipment, $order_shipment ), + ); + + self::send_json_success( $response, $order_shipment, $shipment ); + } + + public static function json_search_orders() { + ob_start(); + + check_ajax_referer( 'search-orders', 'security' ); + + if ( ! current_user_can( 'edit_shop_orders' ) ) { + wp_die( -1 ); + } + + $term = isset( $_GET['term'] ) ? (string) wc_clean( wp_unslash( $_GET['term'] ) ) : ''; + $limit = 0; + + if ( empty( $term ) ) { + wp_die(); + } + + if ( ! is_numeric( $term ) ) { + $ids = wc_order_search( $term ); + } else { + global $wpdb; + + $ids = $wpdb->get_col( + $wpdb->prepare( + "SELECT DISTINCT p1.ID FROM {$wpdb->posts} p1 WHERE p1.ID LIKE %s AND post_type = 'shop_order'", // @codingStandardsIgnoreLine + $wpdb->esc_like( wc_clean( $term ) ) . '%' + ) + ); + } + + $found_orders = array(); + + if ( ! empty( $_GET['exclude'] ) ) { + $ids = array_diff( $ids, array_map( 'absint', (array) wp_unslash( $_GET['exclude'] ) ) ); + } + + foreach ( $ids as $id ) { + if ( $order = wc_get_order( $id ) ) { + $found_orders[ $id ] = sprintf( + esc_html_x( 'Order #%s', 'shipments', 'woocommerce-germanized' ), + $order->get_order_number() + ); + } + } + + /** + * Filter to adjust found orders to filter Shipments. + * + * @param array $result The order search result. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + wp_send_json( apply_filters( 'woocommerce_gzd_json_search_found_shipment_orders', $found_orders ) ); + } + + private static function get_order_status_html( $order_shipment ) { + $status_html = '' . wc_gzd_get_shipment_order_shipping_status_name( $order_shipment->get_shipping_status() ) . ''; + + return $status_html; + } + + /** + * @param \WC_Order $order + * + * @return string[] + */ + private static function get_global_order_status_html( $order ) { + $old_status = $order->get_status(); + $result = array( + 'status' => '', + 'input' => '', + ); + + /** + * Load a clean instance to make sure order status updates are reflected. + */ + $order = wc_get_order( $order->get_id() ); + + /** + * In case the current request has not changed the status do not return html + */ + if ( ! $order || $old_status === $order->get_status() ) { + return $result; + } + ob_start(); + ?> +

+ + +

+ get_status( 'edit' ) ) . '" />'; + + return $result; + } + + private static function get_order_return_status_html( $order_shipment ) { + $status_html = '' . wc_gzd_get_shipment_order_return_status_name( $order_shipment->get_return_status() ) . ''; + + return $status_html; + } + + public static function refresh_shipment_packaging() { + check_ajax_referer( 'refresh-shipment-packaging', 'security' ); + + if ( ! current_user_can( 'edit_shop_orders' ) || ! isset( $_POST['shipment_id'] ) ) { + wp_die( -1 ); + } + + $response_error = array( + 'success' => false, + 'message' => _x( 'There was an error processing the shipment', 'shipments', 'woocommerce-germanized' ), + ); + + $shipment_id = absint( $_POST['shipment_id'] ); + + if ( ! $shipment = wc_gzd_get_shipment( $shipment_id ) ) { + wp_send_json( $response_error ); + } + + $response = array( + 'success' => true, + 'message' => '', + 'shipment_id' => $shipment_id, + 'needs_packaging_refresh' => true, + ); + + $data = array( + 'packaging_id' => isset( $_POST['shipment_packaging_id'][ $shipment_id ] ) ? absint( wc_clean( wp_unslash( $_POST['shipment_packaging_id'][ $shipment_id ] ) ) ) : '', + ); + + $shipment->set_props( $data ); + + $response['fragments'] = array( + '#shipment-' . $shipment->get_id() . ' .shipment-packaging-select' => self::get_packaging_select_html( $shipment ), + ); + + wp_send_json( $response ); + } + + protected static function get_packaging_select_html( $shipment ) { + ob_start(); + include Package::get_path() . '/includes/admin/views/html-order-shipment-packaging-select.php'; + $html = ob_get_clean(); + + return $html; + } + + public static function save_shipments() { + check_ajax_referer( 'edit-shipments', 'security' ); + + if ( ! current_user_can( 'edit_shop_orders' ) || ! isset( $_POST['order_id'] ) ) { + wp_die( -1 ); + } + + $response_error = array( + 'success' => false, + 'message' => _x( 'There was an error processing the shipment', 'shipments', 'woocommerce-germanized' ), + ); + + $response = array( + 'success' => true, + 'message' => '', + ); + + $order_id = absint( $_POST['order_id'] ); + $active = isset( $_POST['active'] ) ? absint( $_POST['active'] ) : 0; + + if ( ! $order = wc_get_order( $order_id ) ) { + wp_send_json( $response_error ); + } + + if ( ! $order_shipment = wc_gzd_get_shipment_order( $order ) ) { + wp_send_json( $response_error ); + } + + // Refresh data + self::refresh_shipments( $order_shipment ); + + // Make sure that we are not applying more + $order_shipment->validate_shipment_item_quantities(); + + // Refresh statuses after adjusting quantities + self::refresh_status( $order_shipment ); + + $order_shipment->save(); + + $response['fragments'] = self::get_shipments_html( $order_shipment, $active ); + + self::send_json_success( $response, $order_shipment ); + } + + /** + * @param Order $order_shipment + * @param int $active + * + * @return array + */ + private static function get_shipments_html( $p_order_shipment, $p_active = 0 ) { + $order_shipment = $p_order_shipment; + $active_shipment = $p_active; + + ob_start(); + include Package::get_path() . '/includes/admin/views/html-order-shipment-list.php'; + $html = ob_get_clean(); + + $order_status_html = self::get_global_order_status_html( $order_shipment->get_order() ); + + $fragments = array( + '#order-shipments-list' => $html, + '.order-shipping-status' => self::get_order_status_html( $order_shipment ), + '.order-return-status' => self::get_order_return_status_html( $order_shipment ), + '.order_data_column p.wc-order-status' => $order_status_html['status'], + 'input[name="post_status"]' => $order_status_html['input'], + ); + + if ( empty( $fragments['.order_data_column p.wc-order-status'] ) ) { + unset( $fragments['.order_data_column p.wc-order-status'] ); + unset( $fragments['input[name="post_status"]'] ); + } + + return $fragments; + } + + public static function get_available_return_shipment_items() { + check_ajax_referer( 'edit-shipments', 'security' ); + + if ( ! current_user_can( 'edit_shop_orders' ) || ! isset( $_POST['order_id'] ) ) { + wp_die( -1 ); + } + + $response_error = array( + 'success' => false, + 'message' => _x( 'There was an error processing the shipment', 'shipments', 'woocommerce-germanized' ), + ); + + $response = array( + 'success' => true, + 'message' => '', + 'html' => '', + ); + + $order_id = absint( $_POST['order_id'] ); + + if ( ! $order_shipment = wc_gzd_get_shipment_order( $order_id ) ) { + wp_send_json( $response_error ); + } + + static::refresh_shipments( $order_shipment ); + + ob_start(); + include Package::get_path() . '/includes/admin/views/html-order-add-return-shipment-items.php'; + $response['html'] = ob_get_clean(); + + self::send_json_success( $response, $order_shipment ); + } + + public static function get_available_shipment_items() { + check_ajax_referer( 'edit-shipments', 'security' ); + + if ( ! current_user_can( 'edit_shop_orders' ) || ! isset( $_POST['shipment_id'] ) ) { + wp_die( -1 ); + } + + $response_error = array( + 'success' => false, + 'message' => _x( 'There was an error processing the shipment', 'shipments', 'woocommerce-germanized' ), + ); + + $response = array( + 'success' => true, + 'message' => '', + 'items' => array(), + ); + + $shipment_id = absint( $_POST['shipment_id'] ); + + if ( ! $shipment = wc_gzd_get_shipment( $shipment_id ) ) { + wp_send_json( $response_error ); + } + + if ( ! $order = $shipment->get_order() ) { + wp_send_json( $response_error ); + } + + if ( ! $order_shipment = wc_gzd_get_shipment_order( $order ) ) { + wp_send_json( $response_error ); + } + + static::refresh_shipments( $order_shipment ); + + if ( 'return' === $shipment->get_type() ) { + $response['items'] = $order_shipment->get_available_items_for_return( + array( + 'shipment_id' => $shipment->get_id(), + 'disable_duplicates' => true, + ) + ); + } else { + $response['items'] = $order_shipment->get_available_items_for_shipment( + array( + 'shipment_id' => $shipment_id, + 'disable_duplicates' => true, + ) + ); + } + + self::send_json_success( $response, $order_shipment ); + } + + public static function add_shipment_item() { + check_ajax_referer( 'edit-shipments', 'security' ); + + if ( ! current_user_can( 'edit_shop_orders' ) || ! isset( $_POST['shipment_id'] ) ) { + wp_die( -1 ); + } + + $response_error = array( + 'success' => false, + 'message' => _x( 'There was an error processing the shipment', 'shipments', 'woocommerce-germanized' ), + ); + + $response = array( + 'success' => true, + 'message' => '', + 'new_item' => '', + ); + + $shipment_id = absint( $_POST['shipment_id'] ); + $original_item_id = isset( $_POST['original_item_id'] ) ? absint( $_POST['original_item_id'] ) : 0; + $item_quantity = isset( $_POST['quantity'] ) ? absint( $_POST['quantity'] ) : false; + + if ( false !== $item_quantity && 0 === $item_quantity ) { + $item_quantity = 1; + } + + if ( empty( $original_item_id ) ) { + wp_send_json( $response_error ); + } + + if ( ! $shipment = wc_gzd_get_shipment( $shipment_id ) ) { + wp_send_json( $response_error ); + } + + if ( ! $order = $shipment->get_order() ) { + wp_send_json( $response_error ); + } + + if ( ! $order_shipment = wc_gzd_get_shipment_order( $order ) ) { + wp_send_json( $response_error ); + } + + static::refresh_shipments( $order_shipment ); + + // Make sure we are working with the shipment from the order + $shipment = $order_shipment->get_shipment( $shipment_id ); + + if ( 'return' === $shipment->get_type() ) { + $item = self::add_shipment_return_item( $order_shipment, $shipment, $original_item_id, $item_quantity ); + } else { + $item = self::add_shipment_order_item( $order_shipment, $shipment, $original_item_id, $item_quantity ); + } + + if ( ! $item ) { + wp_send_json( $response_error ); + } + + ob_start(); + include Package::get_path() . '/includes/admin/views/html-order-shipment-item.php'; + $response['new_item'] = ob_get_clean(); + + $response['fragments'] = array( + '#shipment-' . $shipment->get_id() . ' .item-count:first' => self::get_item_count_html( $shipment, $order_shipment ), + ); + + self::send_json_success( $response, $order_shipment, $shipment ); + } + + /** + * @param Order $order_shipment + * @param ReturnShipment $shipment + * @param integer $parent_item_id + * @param integer $quantity + */ + private static function add_shipment_return_item( $order_shipment, $shipment, $order_item_id, $quantity ) { + $response_error = array( + 'success' => false, + 'message' => _x( 'There was an error processing the shipment', 'shipments', 'woocommerce-germanized' ), + ); + + if ( ! $shipment_item = $order_shipment->get_simple_shipment_item( $order_item_id ) ) { + wp_send_json( $response_error ); + } + + // No duplicates allowed + if ( $shipment->get_item_by_order_item_id( $order_item_id ) ) { + wp_send_json( $response_error ); + } + + // Check max quantity + $quantity_left = $order_shipment->get_item_quantity_left_for_returning( $shipment_item->get_order_item_id() ); + + if ( $quantity ) { + if ( $quantity > $quantity_left ) { + $quantity = $quantity_left; + } + } else { + $quantity = $quantity_left; + } + + if ( $item = wc_gzd_create_return_shipment_item( $shipment, $shipment_item, array( 'quantity' => $quantity ) ) ) { + $shipment->add_item( $item ); + $shipment->save(); + } + + return $item; + } + + /** + * @param Order $order_shipment + * @param SimpleShipment $shipment + * @param integer $order_item_id + * @param integer $quantity + */ + private static function add_shipment_order_item( $order_shipment, $shipment, $order_item_id, $quantity ) { + + $response_error = array( + 'success' => false, + 'message' => _x( 'There was an error processing the shipment', 'shipments', 'woocommerce-germanized' ), + ); + + $order = $order_shipment->get_order(); + + if ( ! $order_item = $order->get_item( $order_item_id ) ) { + wp_send_json( $response_error ); + } + + // No duplicates allowed + if ( $shipment->get_item_by_order_item_id( $order_item_id ) ) { + wp_send_json( $response_error ); + } + + // Check max quantity + $quantity_left = $order_shipment->get_item_quantity_left_for_shipping( $order_item ); + + if ( $quantity ) { + if ( $quantity > $quantity_left ) { + $quantity = $quantity_left; + } + } else { + $quantity = $quantity_left; + } + + if ( $item = wc_gzd_create_shipment_item( $shipment, $order_item, array( 'quantity' => $quantity ) ) ) { + $shipment->add_item( $item ); + $shipment->save(); + } + + return $item; + } + + private static function get_item_count_html( $p_shipment, $p_order_shipment ) { + $shipment = $p_shipment; + + // Refresh the instance to make sure we are working with the same object + $shipment->set_order_shipment( $p_order_shipment ); + + ob_start(); + include Package::get_path() . '/includes/admin/views/html-order-shipment-item-count.php'; + $html = ob_get_clean(); + + return $html; + } + + public static function remove_shipment_item() { + check_ajax_referer( 'edit-shipments', 'security' ); + + if ( ! current_user_can( 'edit_shop_orders' ) || ! isset( $_POST['shipment_id'] ) || ! isset( $_POST['item_id'] ) ) { + wp_die( -1 ); + } + + $response_error = array( + 'success' => false, + 'message' => _x( 'There was an error processing the shipment', 'shipments', 'woocommerce-germanized' ), + ); + + $response = array( + 'success' => true, + 'message' => '', + 'item_id' => '', + ); + + $shipment_id = absint( $_POST['shipment_id'] ); + $item_id = absint( $_POST['item_id'] ); + + if ( ! $shipment = wc_gzd_get_shipment( $shipment_id ) ) { + wp_send_json( $response_error ); + } + + if ( ! $item = $shipment->get_item( $item_id ) ) { + wp_send_json( $response_error ); + } + + if ( ! $order_shipment = wc_gzd_get_shipment_order( $shipment->get_order_id() ) ) { + wp_send_json( $response_error ); + } + + $shipment->remove_item( $item_id ); + $shipment->save(); + + $response['item_id'] = $item_id; + $response['fragments'] = array( + '#shipment-' . $shipment->get_id() . ' .item-count:first' => self::get_item_count_html( $shipment, $order_shipment ), + ); + + self::send_json_success( $response, $order_shipment, $shipment ); + } + + public static function limit_shipment_item_quantity() { + check_ajax_referer( 'edit-shipments', 'security' ); + + if ( ! current_user_can( 'edit_shop_orders' ) || ! isset( $_POST['shipment_id'] ) || ! isset( $_POST['item_id'] ) ) { + wp_die( -1 ); + } + + $response_error = array( + 'success' => false, + 'message' => _x( 'There was an error processing the shipment', 'shipments', 'woocommerce-germanized' ), + ); + + $response = array( + 'success' => true, + 'message' => '', + 'max_quantity' => '', + 'item_id' => '', + ); + + $shipment_id = absint( $_POST['shipment_id'] ); + $item_id = absint( $_POST['item_id'] ); + $quantity = isset( $_POST['quantity'] ) ? (int) $_POST['quantity'] : 1; + $quantity = $quantity <= 0 ? 1 : $quantity; + + if ( ! $shipment = wc_gzd_get_shipment( $shipment_id ) ) { + wp_send_json( $response_error ); + } + + if ( ! $order = $shipment->get_order() ) { + wp_send_json( $response_error ); + } + + if ( ! $order_shipment = wc_gzd_get_shipment_order( $order ) ) { + wp_send_json( $response_error ); + } + + // Make sure the shipment order gets notified about changes + if ( ! $shipment = $order_shipment->get_shipment( $shipment_id ) ) { + wp_send_json( $response_error ); + } + + if ( ! $item = $shipment->get_item( $item_id ) ) { + wp_send_json( $response_error ); + } + + if ( ! $order_item = $order->get_item( $item->get_order_item_id() ) ) { + wp_send_json( $response_error ); + } + + static::refresh_shipments( $order_shipment ); + + $quantity_max = 0; + + if ( 'return' === $shipment->get_type() ) { + $quantity_max = $order_shipment->get_item_quantity_left_for_returning( + $item->get_order_item_id(), + array( + 'exclude_current_shipment' => true, + 'shipment_id' => $shipment->get_id(), + ) + ); + } else { + $quantity_max = $order_shipment->get_item_quantity_left_for_shipping( + $order_item, + array( + 'exclude_current_shipment' => true, + 'shipment_id' => $shipment->get_id(), + ) + ); + } + + $response['item_id'] = $item_id; + $response['max_quantity'] = $quantity_max; + + if ( $quantity > $quantity_max ) { + $quantity = $quantity_max; + } + + $shipment->update_item_quantity( $item_id, $quantity ); + + $response['fragments'] = array( + '#shipment-' . $shipment->get_id() . ' .item-count:first' => self::get_item_count_html( $shipment, $order_shipment ), + ); + + self::send_json_success( $response, $order_shipment, $shipment ); + } + + /** + * @param $response + * @param Order $order_shipment + * @param Shipment|bool $shipment + */ + private static function send_json_success( $response, $order_shipment, $current_shipment = false ) { + + $available_items = $order_shipment->get_available_items_for_shipment(); + $response['shipments'] = array(); + + foreach ( $order_shipment->get_shipments() as $shipment ) { + $shipment->set_order_shipment( $order_shipment ); + + $response['shipments'][ $shipment->get_id() ] = array( + 'is_editable' => $shipment->is_editable(), + 'needs_items' => $shipment->needs_items( array_keys( $available_items ) ), + 'weight' => wc_format_localized_decimal( $shipment->get_content_weight() ), + 'length' => wc_format_localized_decimal( $shipment->get_content_length() ), + 'width' => wc_format_localized_decimal( $shipment->get_content_width() ), + 'height' => wc_format_localized_decimal( $shipment->get_content_height() ), + 'total_weight' => wc_format_localized_decimal( $shipment->get_total_weight() ), + ); + } + + $response['order_needs_new_shipments'] = $order_shipment->needs_shipping(); + $response['order_needs_new_returns'] = $order_shipment->needs_return(); + + if ( $current_shipment ) { + if ( ! isset( $response['fragments'] ) ) { + $response['fragments'] = array(); + } + + $response['needs_packaging_refresh'] = true; + $response['shipment_id'] = $current_shipment->get_id(); + $response['fragments'][ '#shipment-' . $current_shipment->get_id() . ' .shipment-packaging-select' ] = self::get_packaging_select_html( $current_shipment ); + } + + wp_send_json( $response ); + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Api.php b/packages/woocommerce-germanized-shipments/src/Api.php new file mode 100644 index 000000000..51cc8d7c8 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Api.php @@ -0,0 +1,215 @@ +set_data( array_merge( $response->data, self::get_product_data( $product, $context ) ) ); + } + + return $response; + } + + private static function get_product_data( $product, $context = 'view' ) { + $data = array(); + + if ( $shipments_product = wc_gzd_shipments_get_product( $product ) ) { + $data['hs_code'] = $shipments_product->get_hs_code( $context ); + $data['manufacture_country'] = $shipments_product->get_manufacture_country( $context ); + } + + return $data; + } + + /** + * @param \WC_Product $product + * @param $request + * + * @return \WC_Product $product + */ + public static function update_product( $product, $request ) { + if ( $shipments_product = wc_gzd_shipments_get_product( $product ) ) { + if ( isset( $request['hs_code'] ) ) { + $shipments_product->set_hs_code( wc_clean( wp_unslash( $request['hs_code'] ) ) ); + } + + if ( isset( $request['manufacture_country'] ) ) { + $shipments_product->set_manufacture_country( wc_clean( wp_unslash( $request['manufacture_country'] ) ) ); + } + } + + return $product; + } + + public static function remove_status_prefix( $status ) { + if ( 'gzd-' === substr( $status, 0, 4 ) ) { + $status = substr( $status, 4 ); + } + + return $status; + } + + /** + * Extend schema. + * + * @since 1.0.0 + * + * @param array $schema_properties Data used to create the order. + * + * @return array + */ + public static function order_schema( $schema_properties ) { + $statuses = array_map( array( __CLASS__, 'remove_status_prefix' ), array_keys( wc_gzd_get_shipment_order_shipping_statuses() ) ); + + $schema_properties['shipping_status'] = array( + 'description' => _x( 'Shipping status', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'enum' => $statuses, + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ); + + return $schema_properties; + } + + /** + * Extend product variation schema. + * + * @since 1.0.0 + * + * @param array $schema_properties Data used to create the product. + * + * @return array + */ + public static function product_variation_schema( $schema_properties ) { + $schema_properties['hs_code'] = array( + 'description' => _x( 'HS-Code (Customs)', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ); + + $schema_properties['manufacture_country'] = array( + 'description' => _x( 'Country of manufacture (Customs)', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ); + + return $schema_properties; + } + + /** + * Extend product schema. + * + * @since 1.0.0 + * + * @param array $schema_properties Data used to create the product. + * + * @return array + */ + public static function product_schema( $schema_properties ) { + $schema_properties['hs_code'] = array( + 'description' => _x( 'HS-Code (Customs)', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ); + + $schema_properties['manufacture_country'] = array( + 'description' => _x( 'Country of manufacture (Customs)', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ); + + return $schema_properties; + } + + /** + * @param WP_REST_Response $response + * @param $post + * @param WP_REST_Request $request + * + * @return mixed + */ + public static function prepare_order_shipments( $response, $post, $request ) { + $order = wc_get_order( $post ); + $response_order_data = $response->get_data(); + $response_order_data['shipments'] = array(); + $response_order_data['shipping_status'] = 'no-shipping-needed'; + + if ( $order ) { + $order_shipment = wc_gzd_get_shipment_order( $order ); + $shipments = $order_shipment->get_shipments(); + + if ( ! empty( $shipments ) ) { + foreach ( $shipments as $shipment ) { + $response_order_data['shipments'][] = ShipmentsController::prepare_shipment( $shipment, 'view', $request['dp'] ); + } + } + + $response_order_data['shipping_status'] = $order_shipment->get_shipping_status(); + } + + $response->set_data( $response_order_data ); + + return $response; + } + + public static function order_shipments_schema( $schema ) { + $schema['shipments'] = array( + 'description' => _x( 'List of shipments.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'array', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + 'items' => ShipmentsController::get_single_item_schema(), + ); + + return $schema; + } + + protected static function get_shipment_statuses() { + $statuses = array(); + + foreach ( array_keys( wc_gzd_get_shipment_statuses() ) as $status ) { + $statuses[] = str_replace( 'gzd-', '', $status ); + } + + return $statuses; + } + + public static function register_controllers( $controller ) { + $controller['wc/v3']['shipments'] = ShipmentsController::class; + + return $controller; + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Automation.php b/packages/woocommerce-germanized-shipments/src/Automation.php new file mode 100644 index 000000000..1cfa35f9b --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Automation.php @@ -0,0 +1,247 @@ +get_id() ) { + self::maybe_create_shipments( $order ); + } + }, + 150 + ); + }, + 10, + 1 + ); + + add_action( 'woocommerce_new_order', array( __CLASS__, 'maybe_create_shipments' ), 10, 2 ); + add_filter( 'wcs_renewal_order_created', array( __CLASS__, 'maybe_create_subscription_shipments' ), 10 ); + } + + if ( 'yes' === Package::get_setting( 'auto_order_shipped_completed_enable' ) ) { + add_action( 'woocommerce_gzd_shipments_order_shipped', array( __CLASS__, 'mark_order_completed' ), 10 ); + } + + if ( 'yes' === Package::get_setting( 'auto_order_completed_shipped_enable' ) ) { + add_action( 'woocommerce_order_status_changed', array( __CLASS__, 'maybe_mark_shipments_shipped' ), 150, 4 ); + } + } + + /** + * @param $order_id + * @param $old_status + * @param $new_status + * @param WC_Order $order + */ + public static function maybe_mark_shipments_shipped( $order_id, $old_status, $new_status, $order ) { + + /** + * Filter to decide which order status is used to determine if a order + * is completed or not to update contained shipment statuses to shipped. + * Does only take effect if the automation option has been set within the shipment settings. + * + * @param string $status The current order status. + * @param integer $order_id The order id. + * + * @since 3.0.5 + * @package Vendidero/Germanized/Shipments + */ + if ( apply_filters( 'woocommerce_gzd_shipments_order_completed_status', 'completed', $order_id ) === $new_status ) { + + // Make sure that MetaBox is saved before we process automation + if ( self::is_admin_edit_order_request() ) { + add_action( 'woocommerce_process_shop_order_meta', array( __CLASS__, 'mark_shipments_shipped' ), 70 ); + } else { + self::mark_shipments_shipped( $order_id ); + } + } + } + + private static function is_admin_edit_order_request() { + return ( isset( $_POST['action'] ) && 'editpost' === $_POST['action'] && isset( $_POST['post_type'] ) && 'shop_order' === $_POST['post_type'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing + } + + public static function mark_shipments_shipped( $order_id ) { + if ( $order = wc_get_order( $order_id ) ) { + if ( $shipment_order = wc_gzd_get_shipment_order( $order ) ) { + foreach ( $shipment_order->get_simple_shipments() as $shipment ) { + + if ( ! $shipment->is_shipped() ) { + $shipment->update_status( 'shipped' ); + } + } + } + } + } + + /** + * Mark the order as completed if the order is fully shipped. + * + * @param $order_id + */ + public static function mark_order_completed( $order_id ) { + if ( $order = wc_get_order( $order_id ) ) { + + /** + * By default do not mark orders (via invoice) as completed after shipped as + * the order will be shipped before the invoice was paid. + */ + $mark_as_completed = ! in_array( $order->get_payment_method(), array( 'invoice' ), true ) ? true : false; + + /** + * Filter that allows to conditionally disable automatic + * order completion after the shipments are marked as shipped. + * + * @param boolean $mark_as_completed Whether to mark the order as completed or not. + * @param integer $order_id The order id. + * + * @since 3.2.3 + * @package Vendidero/Germanized/Shipments + */ + if ( ! apply_filters( 'woocommerce_gzd_shipment_order_mark_as_completed', $mark_as_completed, $order_id ) ) { + return; + } + + /** + * Filter to adjust the new status of an order after all it's required + * shipments have been marked as shipped. Does only take effect if the automation option has been set + * within the shipment settings. + * + * @param string $status The order status to be used. + * @param integer $order_id The order id. + * + * @since 3.0.5 + * @package Vendidero/Germanized/Shipments + */ + $order->update_status( apply_filters( 'woocommerce_gzd_shipment_order_completed_status', 'completed', $order_id ), _x( 'Order is fully shipped.', 'shipments', 'woocommerce-germanized' ) ); + } + } + + public static function create_shipments( $order, $enable_auto_filter = true ) { + if ( is_numeric( $order ) ) { + $order = wc_get_order( $order ); + } + + if ( ! $order ) { + return; + } + + $shipment_status = Package::get_setting( 'auto_default_status' ); + + if ( empty( $shipment_status ) ) { + $shipment_status = 'processing'; + } + + /** + * Filter to disable automatically creating shipments for a specific order. + * + * @param string $enable Whether to create or not create shipments. + * @param integer $order_id The order id. + * @param WC_Order $order The order instance. + * + * @since 3.1.0 + * @package Vendidero/Germanized/Shipments + */ + if ( $enable_auto_filter && ! apply_filters( 'woocommerce_gzd_auto_create_shipments_for_order', true, $order->get_id(), $order ) ) { + return; + } + + if ( $order_shipment = wc_gzd_get_shipment_order( $order ) ) { + if ( ! apply_filters( 'woocommerce_gzd_auto_create_custom_shipments_for_order', false, $order->get_id(), $order ) ) { + $shipments = $order_shipment->get_simple_shipments(); + + foreach ( $shipments as $shipment ) { + if ( $shipment->is_editable() ) { + $shipment->sync(); + $shipment->sync_items(); + $shipment->save(); + } + } + + if ( $order_shipment->needs_shipping() ) { + $shipment = wc_gzd_create_shipment( $order_shipment, array( 'props' => array( 'status' => $shipment_status ) ) ); + + if ( ! is_wp_error( $shipment ) ) { + $order_shipment->add_shipment( $shipment ); + } + } + } + + do_action( 'woocommerce_gzd_after_auto_create_shipments_for_order', $order->get_id(), $shipment_status, $order ); + } + } + + protected static function get_auto_statuses() { + $statuses = (array) Package::get_setting( 'auto_statuses' ); + $clean_statuses = array(); + + if ( ! empty( $statuses ) ) { + foreach ( $statuses as $status ) { + $status = trim( str_replace( 'wc-', '', $status ) ); + + if ( ! in_array( $status, $clean_statuses, true ) ) { + $clean_statuses[] = $status; + } + } + } + + return $clean_statuses; + } + + public static function maybe_create_shipments( $order_id ) { + $statuses = self::get_auto_statuses(); + $has_status = empty( $statuses ) ? true : false; + + if ( ! $has_status ) { + if ( $order_shipment = wc_gzd_get_shipment_order( $order_id ) ) { + $has_status = $order_shipment->get_order()->has_status( $statuses ); + } + } + + if ( $has_status ) { + // Make sure that MetaBox is saved before we process automation + if ( self::is_admin_edit_order_request() ) { + add_action( 'woocommerce_process_shop_order_meta', array( __CLASS__, 'create_shipments' ), 70 ); + } else { + self::create_shipments( $order_id ); + } + } + } + + public static function maybe_create_subscription_shipments( $renewal_order ) { + self::create_shipments( $renewal_order->get_id() ); + + return $renewal_order; + } +} diff --git a/packages/woocommerce-germanized-shipments/src/DataStores/Label.php b/packages/woocommerce-germanized-shipments/src/DataStores/Label.php new file mode 100644 index 000000000..f468644d3 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/DataStores/Label.php @@ -0,0 +1,557 @@ +set_date_created( time() ); + + $data = array( + 'label_number' => $label->get_number(), + 'label_shipment_id' => $label->get_shipment_id(), + 'label_path' => $label->get_path(), + 'label_product_id' => $label->get_product_id(), + 'label_type' => $label->get_type(), + 'label_shipping_provider' => $label->get_shipping_provider(), + 'label_parent_id' => $label->get_parent_id(), + 'label_date_created' => gmdate( 'Y-m-d H:i:s', $label->get_date_created( 'edit' )->getOffsetTimestamp() ), + 'label_date_created_gmt' => gmdate( 'Y-m-d H:i:s', $label->get_date_created( 'edit' )->getTimestamp() ), + ); + + $wpdb->insert( + $wpdb->gzd_shipment_labels, + $data + ); + + $label_id = $wpdb->insert_id; + + if ( $label_id ) { + $label->set_id( $label_id ); + + $this->save_label_data( $label ); + + $label->save_meta_data(); + $label->apply_changes(); + + $this->clear_caches( $label ); + + $hook_postfix = $this->get_hook_postfix( $label ); + + /** + * Action fires when a new DHL label has been created. + * + * The dynamic portion of this hook, `$hook_postfix` refers to the + * label type e.g. return in case it is not a simple label. + * + * @param integer $label_id The label id. + * @param Label $label The label instance. + * + * @since 3.0.0 + * @package Vendidero/Germanized/DHL + */ + do_action( "woocommerce_gzd_shipment_{$hook_postfix}label_created", $label_id, $label ); + } + } + + /** + * @param \Vendidero\Germanized\Shipments\Labels\Label $label + * + * @return string + */ + protected function get_hook_postfix( $label ) { + $prefix = $label->get_shipping_provider() . '_'; + + if ( 'simple' !== $label->get_type() ) { + $prefix = $prefix . $label->get_type() . '_'; + } + + return $prefix; + } + + /** + * Method to update a label in the database. + * + * @param \Vendidero\Germanized\Shipments\Labels\Label $label Label object. + */ + public function update( &$label ) { + global $wpdb; + + $updated_props = array(); + $core_props = $this->core_props; + $changed_props = array_keys( $label->get_changes() ); + $label_data = array(); + + foreach ( $changed_props as $prop ) { + + if ( ! in_array( $prop, $core_props, true ) ) { + continue; + } + + switch ( $prop ) { + case 'date_created': + $label_data[ 'label' . $prop ] = gmdate( 'Y-m-d H:i:s', $label->{'get_' . $prop}( 'edit' )->getOffsetTimestamp() ); + $label_data[ 'label_' . $prop . '_gmt' ] = gmdate( 'Y-m-d H:i:s', $label->{'get_' . $prop}( 'edit' )->getTimestamp() ); + break; + default: + if ( is_callable( array( $label, 'get_' . $prop ) ) ) { + $label_data[ 'label_' . $prop ] = $label->{'get_' . $prop}( 'edit' ); + } + break; + } + } + + if ( ! empty( $label_data ) ) { + $wpdb->update( + $wpdb->gzd_shipment_labels, + $label_data, + array( 'label_id' => $label->get_id() ) + ); + } + + $this->save_label_data( $label ); + $label->save_meta_data(); + + $label->apply_changes(); + $this->clear_caches( $label ); + + $hook_postfix = $this->get_hook_postfix( $label ); + + /** + * Action fires after a DHL label has been updated in the DB. + * + * The dynamic portion of this hook, `$hook_postfix` refers to the + * label type e.g. return in case it is not a simple label. + * + * @param integer $label_id The label id. + * @param Label $label The label instance. + * @param array $changed_props Properties that have been changed. + * + * @since 3.0.0 + * @package Vendidero/Germanized/DHL + */ + do_action( "woocommerce_gzd_shipment_{$hook_postfix}label_updated", $label->get_id(), $label, $changed_props ); + } + + /** + * Remove a shipment from the database. + * + * @since 3.0.0 + * @param \Vendidero\Germanized\Shipments\Labels\Label $label Label object. + * @param bool $force_delete Unused param. + */ + public function delete( &$label, $force_delete = false ) { + global $wpdb; + + if ( $file = $label->get_file() ) { + wp_delete_file( $file ); + } + + /* + * Delete additional files e.g. export documents + */ + foreach ( $label->get_additional_file_types() as $file_type ) { + if ( $file = $label->get_file( $file_type ) ) { + wp_delete_file( $file ); + } + } + + $wpdb->delete( $wpdb->gzd_shipment_labels, array( 'label_id' => $label->get_id() ), array( '%d' ) ); + $wpdb->delete( $wpdb->gzd_shipment_labelmeta, array( 'gzd_shipment_label_id' => $label->get_id() ), array( '%d' ) ); + + $this->clear_caches( $label ); + + $children = $label->get_children(); + + foreach ( $children as $child ) { + $child->delete( $force_delete ); + } + + $hook_postfix = $this->get_hook_postfix( $label ); + + /** + * Action fires after a DHL label has been deleted from DB. + * + * The dynamic portion of this hook, `$hook_postfix` refers to the + * label type e.g. return in case it is not a simple label. + * + * @param integer $label_id The label id. + * @param \Vendidero\Germanized\DHL\Label $label The label object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/DHL + */ + do_action( "woocommerce_gzd_shipment_{$hook_postfix}label_deleted", $label->get_id(), $label ); + } + + /** + * Read a shipment from the database. + * + * @since 3.0.0 + * + * @param \Vendidero\Germanized\Shipments\Labels\Label $label Label object. + * + * @throws Exception Throw exception if invalid shipment. + */ + public function read( &$label ) { + global $wpdb; + + $data = $wpdb->get_row( + $wpdb->prepare( + "SELECT * FROM {$wpdb->gzd_shipment_labels} WHERE label_id = %d LIMIT 1", + $label->get_id() + ) + ); + + if ( $data ) { + $label->set_props( + array( + 'shipment_id' => $data->label_shipment_id, + 'number' => $data->label_number, + 'path' => $data->label_path, + 'parent_id' => $data->label_parent_id, + 'shipping_provider' => $data->label_shipping_provider, + 'product_id' => $data->label_product_id, + 'date_created' => '0000-00-00 00:00:00' !== $data->label_date_created_gmt ? wc_string_to_timestamp( $data->label_date_created_gmt ) : null, + ) + ); + + $this->read_label_data( $label ); + $label->read_meta_data(); + $label->set_object_read( true ); + + $hook_postfix = $this->get_hook_postfix( $label ); + + /** + * Action fires after reading a DHL label from DB. + * + * The dynamic portion of this hook, `$hook_postfix` refers to the + * label type e.g. return in case it is not a simple label. + * + * @param \Vendidero\Germanized\Shipments\Labels\Label $label The label object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/DHL + */ + do_action( "woocommerce_gzd_shipment_{$hook_postfix}label_loaded", $label ); + } else { + throw new Exception( _x( 'Invalid label.', 'shipments', 'woocommerce-germanized' ) ); + } + } + + /** + * Clear any caches. + * + * @param \Vendidero\Germanized\Shipments\Labels\Label $label Label object. + * @since 3.0.0 + */ + protected function clear_caches( &$label ) { + wp_cache_delete( $label->get_id(), $this->meta_type . '_meta' ); + } + + /* + |-------------------------------------------------------------------------- + | Additional Methods + |-------------------------------------------------------------------------- + */ + + /** + * Get the label type based on label ID. + * + * @param int $label_id Label id. + * @return bool|mixed + */ + public function get_label_data( $label_id ) { + global $wpdb; + + $data = $wpdb->get_row( + $wpdb->prepare( + "SELECT label_type, label_shipping_provider FROM {$wpdb->gzd_shipment_labels} WHERE label_id = %d LIMIT 1", + $label_id + ) + ); + + if ( ! empty( $data ) ) { + return (object) array( + 'shipping_provider' => $data->label_shipping_provider, + 'type' => $data->label_type, + ); + } + + return false; + } + + /** + * Read extra data associated with the shipment. + * + * @param \Vendidero\Germanized\Shipments\Labels\Label $label Label object. + * @since 3.0.0 + */ + protected function read_label_data( &$label ) { + $props = array(); + $meta_keys = $this->internal_meta_keys; + + foreach ( $label->get_extra_data_keys() as $key ) { + $meta_keys[] = '_' . $key; + } + + foreach ( $meta_keys as $meta_key ) { + $props[ substr( $meta_key, 1 ) ] = get_metadata( $this->meta_type, $label->get_id(), $meta_key, true ); + } + + $label->set_props( $props ); + } + + /** + * @param \Vendidero\Germanized\Shipments\Labels\Label $label + */ + protected function save_label_data( &$label ) { + $updated_props = array(); + $meta_key_to_props = array(); + + foreach ( $this->internal_meta_keys as $meta_key ) { + $prop_name = substr( $meta_key, 1 ); + + if ( in_array( $prop_name, $this->core_props, true ) ) { + continue; + } + + $meta_key_to_props[ $meta_key ] = $prop_name; + } + + // Make sure to take extra data (like product url or text for external products) into account. + $extra_data_keys = $label->get_extra_data_keys(); + + foreach ( $extra_data_keys as $key ) { + $meta_key_to_props[ '_' . $key ] = $key; + } + + $props_to_update = $this->get_props_to_update( $label, $meta_key_to_props, $this->meta_type ); + + foreach ( $props_to_update as $meta_key => $prop ) { + + if ( ! is_callable( array( $label, "get_$prop" ) ) ) { + continue; + } + + $value = $label->{"get_$prop"}( 'edit' ); + $value = is_string( $value ) ? wp_slash( $value ) : $value; + + if ( is_bool( $value ) ) { + $value = wc_bool_to_string( $value ); + } + + $updated = $this->update_or_delete_meta( $label, $meta_key, $value ); + + if ( $updated ) { + $updated_props[] = $prop; + } + } + + /** + * Action fires after DHL label meta properties have been updated. + * + * @param \Vendidero\Germanized\Shipments\Labels\Label $label The label object. + * @param array $updated_props The updated properties. + * + * @since 3.0.0 + * @package Vendidero/Germanized/DHL + */ + do_action( 'woocommerce_gzd_shipment_label_object_updated_props', $label, $updated_props ); + } + + /** + * Update meta data in, or delete it from, the database. + * + * Avoids storing meta when it's either an empty string or empty array. + * Other empty values such as numeric 0 and null should still be stored. + * Data-stores can force meta to exist using `must_exist_meta_keys`. + * + * Note: WordPress `get_metadata` function returns an empty string when meta data does not exist. + * + * @param WC_Data $object The WP_Data object (WC_Coupon for coupons, etc). + * @param string $meta_key Meta key to update. + * @param mixed $meta_value Value to save. + * + * @since 3.6.0 Added to prevent empty meta being stored unless required. + * + * @return bool True if updated/deleted. + */ + protected function update_or_delete_meta( $object, $meta_key, $meta_value ) { + if ( in_array( $meta_value, array( array(), '' ), true ) && ! in_array( $meta_key, $this->must_exist_meta_keys, true ) ) { + $updated = delete_metadata( $this->meta_type, $object->get_id(), $meta_key ); + } else { + $updated = update_metadata( $this->meta_type, $object->get_id(), $meta_key, $meta_value ); + } + + return (bool) $updated; + } + + /** + * Get valid WP_Query args from a WC_Order_Query's query variables. + * + * @since 3.0.6 + * @param array $query_vars query vars from a WC_Order_Query. + * @return array + */ + protected function get_wp_query_args( $query_vars ) { + global $wpdb; + + $wp_query_args = parent::get_wp_query_args( $query_vars ); + + // Force type to be existent + if ( isset( $query_vars['type'] ) ) { + $wp_query_args['type'] = $query_vars['type']; + } + + if ( ! isset( $wp_query_args['date_query'] ) ) { + $wp_query_args['date_query'] = array(); + } + + if ( ! isset( $wp_query_args['meta_query'] ) ) { + $wp_query_args['meta_query'] = array(); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query + } + + // Allow Woo to treat these props as date query compatible + $date_queries = array( + 'date_created' => 'post_date', + ); + + foreach ( $date_queries as $query_var_key => $db_key ) { + if ( isset( $query_vars[ $query_var_key ] ) && '' !== $query_vars[ $query_var_key ] ) { + + // Remove any existing meta queries for the same keys to prevent conflicts. + $existing_queries = wp_list_pluck( $wp_query_args['meta_query'], 'key', true ); + $meta_query_index = array_search( $db_key, $existing_queries, true ); + + if ( false !== $meta_query_index ) { + unset( $wp_query_args['meta_query'][ $meta_query_index ] ); + } + + $wp_query_args = $this->parse_date_for_wp_query( $query_vars[ $query_var_key ], $db_key, $wp_query_args ); + } + } + + /** + * Replace date query columns after Woo parsed dates. + * Include table name because otherwise WP_Date_Query won't accept our custom column. + */ + if ( isset( $wp_query_args['date_query'] ) ) { + foreach ( $wp_query_args['date_query'] as $key => $date_query ) { + if ( isset( $date_query['column'] ) && in_array( $date_query['column'], $date_queries, true ) ) { + $wp_query_args['date_query'][ $key ]['column'] = $wpdb->gzd_shipment_labels . '.label_' . array_search( $date_query['column'], $date_queries, true ); + } + } + } + + if ( ! isset( $query_vars['paginate'] ) || ! $query_vars['paginate'] ) { + $wp_query_args['no_found_rows'] = true; + } + + /** + * Filter to adjust the DHL label query args after parsing them. + * + * @param array $wp_query_args Parsed query arguments. + * @param array $query_vars Original query arguments. + * @param Label $data_store The label data store. + * + * @since 3.0.0 + * @package Vendidero/Germanized/DHL + */ + return apply_filters( 'woocommerce_gzd_shipment_label_data_store_get_labels_query', $wp_query_args, $query_vars, $this ); + } + + public function get_query_args( $query_vars ) { + return $this->get_wp_query_args( $query_vars ); + } + + /** + * Table structure is slightly different between meta types, this function will return what we need to know. + * + * @since 3.0.0 + * @return array Array elements: table, object_id_field, meta_id_field + */ + protected function get_db_info() { + global $wpdb; + + $meta_id_field = 'meta_id'; // for some reason users calls this umeta_id so we need to track this as well. + $table = $wpdb->gzd_shipment_labelmeta; + $object_id_field = $this->meta_type . '_id'; + + if ( ! empty( $this->object_id_field_for_meta ) ) { + $object_id_field = $this->object_id_field_for_meta; + } + + return array( + 'table' => $table, + 'object_id_field' => $object_id_field, + 'meta_id_field' => $meta_id_field, + ); + } + + public function get_label_count() { + global $wpdb; + + return absint( $wpdb->get_var( "SELECT COUNT( * ) FROM {$wpdb->gzd_shipment_labels}" ) ); + } +} diff --git a/packages/woocommerce-germanized-shipments/src/DataStores/Packaging.php b/packages/woocommerce-germanized-shipments/src/DataStores/Packaging.php new file mode 100644 index 000000000..984a6790c --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/DataStores/Packaging.php @@ -0,0 +1,694 @@ +set_date_created( time() ); + + $data = array( + 'packaging_type' => $packaging->get_type(), + 'packaging_description' => $packaging->get_description(), + 'packaging_weight' => $packaging->get_weight(), + 'packaging_max_content_weight' => $packaging->get_max_content_weight(), + 'packaging_length' => $packaging->get_length(), + 'packaging_width' => $packaging->get_width(), + 'packaging_height' => $packaging->get_height(), + 'packaging_order' => $packaging->get_order(), + 'packaging_date_created' => gmdate( 'Y-m-d H:i:s', $packaging->get_date_created( 'edit' )->getOffsetTimestamp() ), + 'packaging_date_created_gmt' => gmdate( 'Y-m-d H:i:s', $packaging->get_date_created( 'edit' )->getTimestamp() ), + ); + + $wpdb->insert( + $wpdb->gzd_packaging, + $data + ); + + $packaging_id = $wpdb->insert_id; + + if ( $packaging_id ) { + $packaging->set_id( $packaging_id ); + + $this->save_packaging_data( $packaging ); + + $packaging->save_meta_data(); + $packaging->apply_changes(); + + $this->clear_caches( $packaging ); + + /** + * Action that indicates that a new Packaging has been created in the DB. + * + * @param integer $packaging_id The packaging id. + * @param \Vendidero\Germanized\Shipments\Packaging $packaging The packaging instance. + * + * @since 3.3.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_new_packaging', $packaging_id, $packaging ); + } + } + + /** + * Method to update a packaging in the database. + * + * @param \Vendidero\Germanized\Shipments\Packaging $packaging Packaging object. + */ + public function update( &$packaging ) { + global $wpdb; + + $updated_props = array(); + $core_props = $this->core_props; + $changed_props = array_keys( $packaging->get_changes() ); + $packaging_data = array(); + + foreach ( $changed_props as $prop ) { + + if ( ! in_array( $prop, $core_props, true ) ) { + continue; + } + + switch ( $prop ) { + case 'date_created': + if ( is_callable( array( $packaging, 'get_' . $prop ) ) ) { + $packaging_data[ 'packaging_' . $prop ] = gmdate( 'Y-m-d H:i:s', $packaging->{'get_' . $prop}( 'edit' )->getOffsetTimestamp() ); + $packaging_data[ 'packaging_' . $prop . '_gmt' ] = gmdate( 'Y-m-d H:i:s', $packaging->{'get_' . $prop}( 'edit' )->getTimestamp() ); + } + break; + default: + if ( is_callable( array( $packaging, 'get_' . $prop ) ) ) { + $packaging_data[ 'packaging_' . $prop ] = $packaging->{'get_' . $prop}( 'edit' ); + } + break; + } + } + + if ( ! empty( $packaging_data ) ) { + $wpdb->update( + $wpdb->gzd_packaging, + $packaging_data, + array( 'packaging_id' => $packaging->get_id() ) + ); + } + + $this->save_packaging_data( $packaging ); + + $packaging->save_meta_data(); + $packaging->apply_changes(); + + $this->clear_caches( $packaging ); + + /** + * Action that indicates that a Packaging has been updated in the DB. + * + * @param integer $packaging_id The packaging id. + * @param \Vendidero\Germanized\Shipments\Packaging $packaging The packaging instance. + * + * @since 3.3.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_packaging_updated', $packaging->get_id(), $packaging ); + } + + /** + * Remove a Packaging from the database. + * + * @since 3.0.0 + * @param \Vendidero\Germanized\Shipments\Packaging $packaging Packaging object. + * @param bool $force_delete Unused param. + */ + public function delete( &$packaging, $force_delete = false ) { + global $wpdb; + + $wpdb->delete( $wpdb->gzd_packaging, array( 'packaging_id' => $packaging->get_id() ), array( '%d' ) ); + $wpdb->delete( $wpdb->gzd_packagingmeta, array( 'gzd_packaging_id' => $packaging->get_id() ), array( '%d' ) ); + + $this->clear_caches( $packaging ); + + /** + * Action that indicates that a Packaging has been deleted from the DB. + * + * @param integer $packaging_id The packaging id. + * @param \Vendidero\Germanized\Shipments\Packaging $packaging The packaging instance. + * + * @since 3.3.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_packaging_deleted', $packaging->get_id(), $packaging ); + } + + /** + * Read a Packaging from the database. + * + * @since 3.3.0 + * + * @param \Vendidero\Germanized\Shipments\Packaging $packaging Packaging object. + * + * @throws Exception Throw exception if invalid packaging. + */ + public function read( &$packaging ) { + global $wpdb; + + $data = $wpdb->get_row( + $wpdb->prepare( + "SELECT * FROM {$wpdb->gzd_packaging} WHERE packaging_id = %d LIMIT 1", + $packaging->get_id() + ) + ); + + if ( $data ) { + $packaging->set_props( + array( + 'type' => $data->packaging_type, + 'description' => $data->packaging_description, + 'weight' => $data->packaging_weight, + 'max_content_weight' => $data->packaging_max_content_weight, + 'length' => $data->packaging_length, + 'width' => $data->packaging_width, + 'height' => $data->packaging_height, + 'order' => $data->packaging_order, + 'date_created' => '0000-00-00 00:00:00' !== $data->packaging_date_created_gmt ? wc_string_to_timestamp( $data->packaging_date_created_gmt ) : null, + ) + ); + + $this->read_packaging_data( $packaging ); + + $packaging->read_meta_data(); + $packaging->set_object_read( true ); + + /** + * Action that indicates that a Packaging has been loaded from DB. + * + * @param \Vendidero\Germanized\Shipments\Packaging $packaging The Packaging object. + * + * @since 3.3.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_packaging_loaded', $packaging ); + } else { + throw new Exception( _x( 'Invalid packaging.', 'shipments', 'woocommerce-germanized' ) ); + } + } + + /** + * Clear any caches. + * + * @param \Vendidero\Germanized\Shipments\Packaging $packaging Packaging object. + * @since 3.0.0 + */ + protected function clear_caches( &$packaging ) { + wp_cache_delete( $packaging->get_id(), $this->meta_type . '_meta' ); + wp_cache_delete( 'packaging-list', 'packaging' ); + } + + /* + |-------------------------------------------------------------------------- + | Additional Methods + |-------------------------------------------------------------------------- + */ + + /** + * Get the packaging type based on ID. + * + * @param int $packaging_id Packaging id. + * @return string + */ + public function get_packaging_type( $packing_id ) { + global $wpdb; + + $type = $wpdb->get_col( + $wpdb->prepare( + "SELECT packaging_type FROM {$wpdb->gzd_packaging} WHERE packaging_id = %d LIMIT 1", + $packing_id + ) + ); + + return ! empty( $type ) ? $type[0] : false; + } + + /** + * Read extra data associated with the Packaging. + * + * @param \Vendidero\Germanized\Shipments\Packaging $packaging Packaging object. + * @since 3.0.0 + */ + protected function read_packaging_data( &$packaging ) { + $props = array(); + + foreach ( $this->internal_meta_keys as $meta_key ) { + $props[ substr( $meta_key, 1 ) ] = get_metadata( 'gzd_packaging', $packaging->get_id(), $meta_key, true ); + } + + $packaging->set_props( $props ); + } + + /** + * @param \Vendidero\Germanized\Shipments\Packaging $packaging + */ + protected function save_packaging_data( &$packaging ) { + $updated_props = array(); + $meta_key_to_props = array(); + + foreach ( $this->internal_meta_keys as $meta_key ) { + $prop_name = substr( $meta_key, 1 ); + + if ( in_array( $prop_name, $this->core_props, true ) ) { + continue; + } + + $meta_key_to_props[ $meta_key ] = $prop_name; + } + + $props_to_update = $this->get_props_to_update( $packaging, $meta_key_to_props, $this->meta_type ); + + foreach ( $props_to_update as $meta_key => $prop ) { + + if ( ! is_callable( array( $packaging, "get_$prop" ) ) ) { + continue; + } + + $value = $packaging->{"get_$prop"}( 'edit' ); + $value = is_string( $value ) ? wp_slash( $value ) : $value; + + $updated = $this->update_or_delete_meta( $packaging, $meta_key, $value ); + + if ( $updated ) { + $updated_props[] = $prop; + } + } + + /** + * Action that fires after updating a Packaging's properties. + * + * @param \Vendidero\Germanized\Shipments\Packaging $packaging The Packaging object. + * @param array $changed_props The updated properties. + * + * @since 3.3.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_packaging_object_updated_props', $packaging, $updated_props ); + } + + /** + * Update meta data in, or delete it from, the database. + * + * Avoids storing meta when it's either an empty string or empty array. + * Other empty values such as numeric 0 and null should still be stored. + * Data-stores can force meta to exist using `must_exist_meta_keys`. + * + * Note: WordPress `get_metadata` function returns an empty string when meta data does not exist. + * + * @param WC_Data $object The WP_Data object (WC_Coupon for coupons, etc). + * @param string $meta_key Meta key to update. + * @param mixed $meta_value Value to save. + * + * @since 3.6.0 Added to prevent empty meta being stored unless required. + * + * @return bool True if updated/deleted. + */ + protected function update_or_delete_meta( $object, $meta_key, $meta_value ) { + if ( in_array( $meta_value, array( array(), '' ), true ) && ! in_array( $meta_key, $this->must_exist_meta_keys, true ) ) { + $updated = delete_metadata( $this->meta_type, $object->get_id(), $meta_key ); + } else { + $updated = update_metadata( $this->meta_type, $object->get_id(), $meta_key, $meta_value ); + } + + return (bool) $updated; + } + + /** + * Get valid WP_Query args from a WC_Order_Query's query variables. + * + * @since 3.0.6 + * @param array $query_vars query vars from a WC_Order_Query. + * @return array + */ + protected function get_wp_query_args( $query_vars ) { + global $wpdb; + + $wp_query_args = parent::get_wp_query_args( $query_vars ); + + // Force type to be existent + if ( isset( $query_vars['type'] ) ) { + $wp_query_args['type'] = $query_vars['type']; + } + + if ( ! isset( $wp_query_args['date_query'] ) ) { + $wp_query_args['date_query'] = array(); + } + + if ( ! isset( $wp_query_args['meta_query'] ) ) { + $wp_query_args['meta_query'] = array(); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query + } + + // Allow Woo to treat these props as date query compatible + $date_queries = array( + 'date_created', + ); + + foreach ( $date_queries as $db_key ) { + if ( isset( $query_vars[ $db_key ] ) && '' !== $query_vars[ $db_key ] ) { + + // Remove any existing meta queries for the same keys to prevent conflicts. + $existing_queries = wp_list_pluck( $wp_query_args['meta_query'], 'key', true ); + $meta_query_index = array_search( $db_key, $existing_queries, true ); + + if ( false !== $meta_query_index ) { + unset( $wp_query_args['meta_query'][ $meta_query_index ] ); + } + + $date_query_args = $this->parse_date_for_wp_query( $query_vars[ $db_key ], 'post_date', array() ); + + /** + * Replace date query columns after Woo parsed dates. + * Include table name because otherwise WP_Date_Query won't accept our custom column. + */ + if ( isset( $date_query_args['date_query'] ) && ! empty( $date_query_args['date_query'] ) ) { + $date_query = $date_query_args['date_query'][0]; + + if ( 'post_date' === $date_query['column'] ) { + $date_query['column'] = $wpdb->gzd_shipments . '.shipment_' . $db_key; + } + + $wp_query_args['date_query'][] = $date_query; + } + } + } + + if ( ! isset( $query_vars['paginate'] ) || ! $query_vars['paginate'] ) { + $wp_query_args['no_found_rows'] = true; + } + + /** + * Filter to adjust Packaging query arguments after parsing. + * + * @param array $wp_query_args Array containing parsed query arguments. + * @param array $query_vars The original query arguments. + * @param Packaging $data_store The packaging data store object. + * + * @since 3.3.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_packaging_data_store_get_shipments_query', $wp_query_args, $query_vars, $this ); + } + + public function get_packaging_list( $args = array() ) { + global $wpdb; + + $all_types = array_keys( wc_gzd_get_packaging_types() ); + + $args = wp_parse_args( + $args, + array( + 'type' => $all_types, + ) + ); + + if ( ! is_array( $args['type'] ) ) { + $args['type'] = array( $args['type'] ); + } + + $types = array_filter( wc_clean( $args['type'] ) ); + $types = empty( $types ) ? $all_types : $types; + + $query = " + SELECT packaging_id FROM {$wpdb->gzd_packaging} + WHERE packaging_type IN ( '" . implode( "','", $types ) . "' ) + ORDER BY packaging_order ASC + "; + + if ( $all_types === $types ) { + // Get from cache if available. + $results = wp_cache_get( 'packaging-list', 'packaging' ); + + if ( false === $results ) { + $results = $wpdb->get_results( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + + wp_cache_set( 'packaging-list', $results, 'packaging' ); + } + } else { + $results = $wpdb->get_results( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + } + + foreach ( $results as $key => $packaging ) { + $results[ $key ] = wc_gzd_get_packaging( $packaging ); + } + + return $results; + } + + /** + * @param \Vendidero\Germanized\Shipments\Shipment $shipment + * @param \Vendidero\Germanized\Shipments\Packaging|PackagingBox $packaging + * + * @return bool + */ + public function shipment_fits_into_packaging_naive( $shipment, $packaging ) { + if ( is_a( $packaging, '\Vendidero\Germanized\Shipments\Packing\PackagingBox' ) ) { + $packaging = $packaging->getReference(); + } + + if ( ! $packaging ) { + return false; + } + + $weight = (float) wc_format_decimal( empty( $shipment->get_content_weight() ) ? 0 : wc_get_weight( $shipment->get_content_weight(), wc_gzd_get_packaging_weight_unit(), $shipment->get_weight_unit() ), 1 ); + $volume = (float) wc_format_decimal( empty( $shipment->get_content_volume() ) ? 0 : wc_gzd_get_volume_dimension( $shipment->get_content_volume(), wc_gzd_get_packaging_dimension_unit(), $shipment->get_dimension_unit() ), 1 ); + $fits = true; + $packaging_volume = (float) $packaging->get_length() * (float) $packaging->get_width() * (float) $packaging->get_height(); + + /** + * The packaging does not fit in case: + * - total weight is greater than it's maximum capability + * - the total volume is greater than the packaging volume + */ + if ( ! empty( $packaging->get_max_content_weight() ) && $weight > $packaging->get_max_content_weight() ) { + $fits = false; + } elseif ( $volume > $packaging_volume ) { + $fits = false; + } + + return $fits; + } + + /** + * @param \Vendidero\Germanized\Shipments\Shipment $shipment + * + * @return \Vendidero\Germanized\Shipments\Packaging[] + */ + public function find_available_packaging_for_shipment( $shipment ) { + $packaging_available = array(); + $items_to_pack = $shipment->get_items_to_pack(); + $results = false; + + // Get from cache if available. + if ( $shipment->get_id() > 0 ) { + $results = wp_cache_get( 'available-packaging-' . $shipment->get_id(), 'shipments' ); + } + + if ( false === $results && count( $items_to_pack ) > 0 ) { + $available_packaging_ids = array(); + + if ( Package::is_packing_supported() ) { + $packaging_list = wc_gzd_get_packaging_list(); + $items = \DVDoug\BoxPacker\ItemList::fromArray( $items_to_pack ); + + foreach ( $packaging_list as $packaging ) { + /** + * Make sure to only check naively fitting packaging to improve performance + */ + if ( ! $this->shipment_fits_into_packaging_naive( $shipment, $packaging ) ) { + continue; + } + + $box = new PackagingBox( $packaging ); + $org_size = count( $items_to_pack ); + + $packer = new VolumePacker( $box, $items ); + $packed = $packer->pack(); + + if ( count( $packed->getItems() ) === $org_size ) { + $packaging_available[] = $packaging; + $available_packaging_ids[] = $packaging->get_id(); + } + } + } else { + global $wpdb; + + $weight = wc_format_decimal( empty( $shipment->get_weight() ) ? 0 : wc_get_weight( $shipment->get_weight(), wc_gzd_get_packaging_weight_unit(), $shipment->get_weight_unit() ), 1 ); + $length = wc_format_decimal( empty( $shipment->get_length() ) ? 0 : wc_get_dimension( $shipment->get_length(), wc_gzd_get_packaging_dimension_unit(), $shipment->get_dimension_unit() ), 1 ); + $width = wc_format_decimal( empty( $shipment->get_width() ) ? 0 : wc_get_dimension( $shipment->get_width(), wc_gzd_get_packaging_dimension_unit(), $shipment->get_dimension_unit() ), 1 ); + $height = wc_format_decimal( empty( $shipment->get_height() ) ? 0 : wc_get_dimension( $shipment->get_height(), wc_gzd_get_packaging_dimension_unit(), $shipment->get_dimension_unit() ), 1 ); + + $types = array_keys( wc_gzd_get_packaging_types() ); + $threshold = apply_filters( 'woocommerce_gzd_shipment_packaging_match_threshold', 0, $shipment ); + + $query_sql = "SELECT + packaging_id, + (packaging_length - %f) AS length_diff, + (packaging_width - %f) AS width_diff, + (packaging_height - %f) AS height_diff, + ((packaging_length - %f) + (packaging_width - %f) + (packaging_height - %f)) AS total_diff + FROM {$wpdb->gzd_packaging} + WHERE ( packaging_max_content_weight = 0 OR packaging_max_content_weight >= %f ) AND packaging_type IN ( '" . implode( "','", $types ) . "' ) + HAVING length_diff >= %f AND width_diff >= %f AND height_diff >= %f + ORDER BY total_diff ASC, packaging_weight ASC, packaging_order ASC + "; + + $query = $wpdb->prepare( $query_sql, $length, $width, $height, $length, $width, $height, $weight, $threshold, $threshold, $threshold ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + $results = $wpdb->get_results( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + + if ( $results ) { + foreach ( $results as $result ) { + $available_packaging_ids[] = $result->packaging_id; + $packaging_available[] = wc_gzd_get_packaging( $result->packaging_id ); + } + } + } + + wp_cache_set( 'available-packaging-' . $shipment->get_id(), $available_packaging_ids, 'shipments' ); + } elseif ( count( $items_to_pack ) <= 0 ) { + $packaging_available = wc_gzd_get_packaging_list(); + } else { + foreach ( (array) $results as $packaging_id ) { + $packaging_available[] = wc_gzd_get_packaging( $packaging_id ); + } + } + + return apply_filters( 'woocommerce_gzd_find_available_packaging_for_shipment', $this->sort_packaging_list( $packaging_available ), $shipment ); + } + + protected function sort_packaging_list( $packaging ) { + usort( $packaging, array( $this, 'sort_packaging_list_callback' ) ); + + return $packaging; + } + + /** + * @param \Vendidero\Germanized\Shipments\Packaging $packaging_a + * @param \Vendidero\Germanized\Shipments\Packaging $packaging_b + * + * @return int + */ + protected function sort_packaging_list_callback( $packaging_a, $packaging_b ) { + if ( $packaging_a->get_volume() === $packaging_b->get_volume() ) { + return 0; + } + + return ( $packaging_a->get_volume() > $packaging_b->get_volume() ) ? 1 : -1; + } + + /** + * @param \Vendidero\Germanized\Shipments\Shipment $shipment + * @param string|array $types + * + * @return \Vendidero\Germanized\Shipments\Packaging|false + */ + public function find_best_match_for_shipment( $shipment ) { + $results = $this->find_available_packaging_for_shipment( $shipment ); + $packaging = false; + + if ( ! empty( $results ) ) { + $packaging = $results[0]; + + /** + * In case more than one packaging is available - choose the default packaging in case it is available. + */ + if ( count( $results ) > 1 ) { + $default_packaging_id = Package::get_setting( 'default_packaging' ); + + if ( ! empty( $default_packaging_id ) ) { + $default_packaging_id = absint( $default_packaging_id ); + + foreach ( $results as $result ) { + if ( $result->get_id() === $default_packaging_id ) { + $packaging = $result; + break; + } + } + } + } + } + + return apply_filters( 'woocommerce_gzd_find_best_matching_packaging_for_shipment', $packaging, $shipment ); + } + + /** + * Table structure is slightly different between meta types, this function will return what we need to know. + * + * @since 3.0.0 + * @return array Array elements: table, object_id_field, meta_id_field + */ + protected function get_db_info() { + global $wpdb; + + $meta_id_field = 'meta_id'; // for some reason users calls this umeta_id so we need to track this as well. + $table = $wpdb->gzd_packagingmeta; + $object_id_field = $this->meta_type . '_id'; + + if ( ! empty( $this->object_id_field_for_meta ) ) { + $object_id_field = $this->object_id_field_for_meta; + } + + return array( + 'table' => $table, + 'object_id_field' => $object_id_field, + 'meta_id_field' => $meta_id_field, + ); + } + + public function get_query_args( $query_vars ) { + return $this->get_wp_query_args( $query_vars ); + } +} diff --git a/packages/woocommerce-germanized-shipments/src/DataStores/Shipment.php b/packages/woocommerce-germanized-shipments/src/DataStores/Shipment.php new file mode 100644 index 000000000..3011ca443 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/DataStores/Shipment.php @@ -0,0 +1,720 @@ +set_date_created( time() ); + $shipment->set_weight_unit( get_option( 'woocommerce_weight_unit', 'kg' ) ); + $shipment->set_dimension_unit( get_option( 'woocommerce_dimension_unit', 'cm' ) ); + + $data = array( + 'shipment_country' => $shipment->get_country(), + 'shipment_order_id' => is_callable( array( $shipment, 'get_order_id' ) ) ? $shipment->get_order_id() : 0, + 'shipment_parent_id' => is_callable( array( $shipment, 'get_parent_id' ) ) ? $shipment->get_parent_id() : 0, + 'shipment_tracking_id' => $shipment->get_tracking_id(), + 'shipment_status' => $this->get_status( $shipment ), + 'shipment_search_index' => $this->get_search_index( $shipment ), + 'shipment_packaging_id' => $shipment->get_packaging_id(), + 'shipment_type' => $shipment->get_type(), + 'shipment_shipping_provider' => $shipment->get_shipping_provider(), + 'shipment_shipping_method' => $shipment->get_shipping_method(), + 'shipment_date_created' => gmdate( 'Y-m-d H:i:s', $shipment->get_date_created( 'edit' )->getOffsetTimestamp() ), + 'shipment_date_created_gmt' => gmdate( 'Y-m-d H:i:s', $shipment->get_date_created( 'edit' )->getTimestamp() ), + 'shipment_version' => Package::get_version(), + ); + + if ( $shipment->get_date_sent() ) { + $data['shipment_date_sent'] = gmdate( 'Y-m-d H:i:s', $shipment->get_date_sent( 'edit' )->getOffsetTimestamp() ); + $data['shipment_date_sent_gmt'] = gmdate( 'Y-m-d H:i:s', $shipment->get_date_sent( 'edit' )->getTimestamp() ); + } + + if ( is_callable( array( $shipment, 'get_est_delivery_date' ) ) && $shipment->get_est_delivery_date() ) { + $data['shipment_est_delivery_date'] = gmdate( 'Y-m-d H:i:s', $shipment->get_est_delivery_date( 'edit' )->getOffsetTimestamp() ); + $data['shipment_est_delivery_date_gmt'] = gmdate( 'Y-m-d H:i:s', $shipment->get_est_delivery_date( 'edit' )->getTimestamp() ); + } + + $wpdb->insert( + $wpdb->gzd_shipments, + $data + ); + + $shipment_id = $wpdb->insert_id; + + if ( $shipment_id ) { + $shipment->set_id( $shipment_id ); + + $this->save_shipment_data( $shipment ); + + $shipment->save_meta_data(); + $shipment->apply_changes(); + + $this->clear_caches( $shipment ); + + $hook_postfix = $this->get_hook_postfix( $shipment ); + + /** + * Action that indicates that a new Shipment has been created in the DB. + * + * The dynamic portion of this hook, `$hook_postfix` refers to the + * shipment type in case it is not a simple shipment. + * + * @param integer $shipment_id The shipment id. + * @param Shipment $shipment The shipment instance. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( "woocommerce_gzd_new_{$hook_postfix}shipment", $shipment_id, $shipment ); + } + } + + /** + * Get the status to save to the object. + * + * @since 3.6.0 + * @param \Vendidero\Germanized\Shipments\Shipment $shipment Shipment object. + * @return string + */ + protected function get_status( $shipment ) { + $shipment_status = $shipment->get_status( 'edit' ); + + if ( ! $shipment_status ) { + /** This filter is documented in src/Shipment.php */ + $shipment_status = apply_filters( 'woocommerce_gzd_get_shipment_default_status', 'gzd-draft' ); + } + + $valid_statuses = array_keys( wc_gzd_get_shipment_statuses() ); + + // Add a gzd- prefix to the status. + if ( in_array( 'gzd-' . $shipment_status, $valid_statuses, true ) ) { + $shipment_status = 'gzd-' . $shipment_status; + } + + return $shipment_status; + } + + /** + * Method to update a shipment in the database. + * + * @param \Vendidero\Germanized\Shipments\Shipment $shipment Shipment object. + */ + public function update( &$shipment ) { + global $wpdb; + + $updated_props = array(); + $core_props = $this->core_props; + $changed_props = array_keys( $shipment->get_changes() ); + $shipment_data = array(); + + if ( '' === $shipment->get_weight_unit( 'edit' ) ) { + $shipment->set_weight_unit( get_option( 'woocommerce_weight_unit', 'kg' ) ); + } + + if ( '' === $shipment->get_dimension_unit( 'edit' ) ) { + $shipment->set_dimension_unit( get_option( 'woocommerce_dimension_unit', 'cm' ) ); + } + + // Make sure country in core props is updated as soon as the address changes + if ( in_array( 'address', $changed_props, true ) ) { + $changed_props[] = 'country'; + + // Update search index + $shipment_data['shipment_search_index'] = $this->get_search_index( $shipment ); + } + + // Shipping provider has changed - lets remove existing label + if ( in_array( 'shipping_provider', $changed_props, true ) ) { + + if ( $shipment->supports_label() && $shipment->has_label() ) { + $shipment->get_label()->delete(); + } + } + + foreach ( $changed_props as $prop ) { + + if ( ! in_array( $prop, $core_props, true ) ) { + continue; + } + + switch ( $prop ) { + case 'status': + $shipment_data[ 'shipment_' . $prop ] = $this->get_status( $shipment ); + break; + case 'date_created': + case 'date_sent': + case 'est_delivery_date': + if ( is_callable( array( $shipment, 'get_' . $prop ) ) ) { + $shipment_data[ 'shipment_' . $prop ] = gmdate( 'Y-m-d H:i:s', $shipment->{'get_' . $prop}( 'edit' )->getOffsetTimestamp() ); + $shipment_data[ 'shipment_' . $prop . '_gmt' ] = gmdate( 'Y-m-d H:i:s', $shipment->{'get_' . $prop}( 'edit' )->getTimestamp() ); + } + break; + default: + if ( is_callable( array( $shipment, 'get_' . $prop ) ) ) { + $shipment_data[ 'shipment_' . $prop ] = $shipment->{'get_' . $prop}( 'edit' ); + } + break; + } + } + + if ( ! empty( $shipment_data ) ) { + $shipment_data['shipment_search_index'] = $this->get_search_index( $shipment ); + + $wpdb->update( + $wpdb->gzd_shipments, + $shipment_data, + array( 'shipment_id' => $shipment->get_id() ) + ); + } + + $this->save_shipment_data( $shipment ); + + $shipment->save_meta_data(); + $shipment->apply_changes(); + + $this->clear_caches( $shipment ); + + $hook_postfix = $this->get_hook_postfix( $shipment ); + + /** + * Action that indicates that a Shipment has been updated in the DB. + * + * The dynamic portion of this hook, `$hook_postfix` refers to the + * shipment type in case it is not a simple shipment. + * + * @param integer $shipment_id The shipment id. + * @param Shipment $shipment The shipment instance. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( "woocommerce_gzd_{$hook_postfix}shipment_updated", $shipment->get_id(), $shipment ); + } + + /** + * Remove a shipment from the database. + * + * @since 3.0.0 + * @param \Vendidero\Germanized\Shipments\Shipment $shipment Shipment object. + * @param bool $force_delete Unused param. + */ + public function delete( &$shipment, $force_delete = false ) { + global $wpdb; + + $wpdb->delete( $wpdb->gzd_shipments, array( 'shipment_id' => $shipment->get_id() ), array( '%d' ) ); + $wpdb->delete( $wpdb->gzd_shipmentmeta, array( 'gzd_shipment_id' => $shipment->get_id() ), array( '%d' ) ); + + $this->delete_items( $shipment ); + $this->clear_caches( $shipment ); + + $hook_postfix = $this->get_hook_postfix( $shipment ); + + /** + * Action that indicates that a Shipment has been deleted from the DB. + * + * The dynamic portion of this hook, `$hook_postfix` refers to the + * shipment type in case it is not a simple shipment. + * + * @param integer $shipment_id The shipment id. + * @param \Vendidero\Germanized\Shipments\Shipment $shipment The shipment object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( "woocommerce_gzd_{$hook_postfix}shipment_deleted", $shipment->get_id(), $shipment ); + } + + /** + * Read a shipment from the database. + * + * @since 3.0.0 + * + * @param \Vendidero\Germanized\Shipments\Shipment $shipment Shipment object. + * + * @throws Exception Throw exception if invalid shipment. + */ + public function read( &$shipment ) { + global $wpdb; + + $data = $wpdb->get_row( + $wpdb->prepare( + "SELECT * FROM {$wpdb->gzd_shipments} WHERE shipment_id = %d LIMIT 1", + $shipment->get_id() + ) + ); + + if ( $data ) { + $shipment->set_props( + array( + 'order_id' => $data->shipment_order_id, + 'parent_id' => $data->shipment_parent_id, + 'country' => $data->shipment_country, + 'tracking_id' => $data->shipment_tracking_id, + 'shipping_provider' => $data->shipment_shipping_provider, + 'shipping_method' => $data->shipment_shipping_method, + 'packaging_id' => $data->shipment_packaging_id, + 'date_created' => $this->is_valid_timestamp( $data->shipment_date_created_gmt ) ? wc_string_to_timestamp( $data->shipment_date_created_gmt ) : null, + 'date_sent' => $this->is_valid_timestamp( $data->shipment_date_sent_gmt ) ? wc_string_to_timestamp( $data->shipment_date_sent_gmt ) : null, + 'est_delivery_date' => $this->is_valid_timestamp( $data->shipment_est_delivery_date_gmt ) ? wc_string_to_timestamp( $data->shipment_est_delivery_date_gmt ) : null, + 'status' => $data->shipment_status, + 'version' => $data->shipment_version, + ) + ); + + $this->read_shipment_data( $shipment ); + + $shipment->read_meta_data(); + $shipment->set_object_read( true ); + + $hook_postfix = $this->get_hook_postfix( $shipment ); + + /** + * Action that indicates that a Shipment has been loaded from DB. + * + * The dynamic portion of this hook, `$hook_postfix` refers to the + * shipment type in case it is not a simple shipment. + * + * @param \Vendidero\Germanized\Shipments\Shipment $shipment The shipment object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( "woocommerce_gzd_{$hook_postfix}shipment_loaded", $shipment ); + } else { + throw new Exception( _x( 'Invalid shipment.', 'shipments', 'woocommerce-germanized' ) ); + } + } + + protected function is_valid_timestamp( $mysql_date ) { + return ( '0000-00-00 00:00:00' === $mysql_date || null === $mysql_date ) ? false : true; + } + + /** + * Clear any caches. + * + * @param \Vendidero\Germanized\Shipments\Shipment $shipment Shipment object. + * @since 3.0.0 + */ + protected function clear_caches( &$shipment ) { + wp_cache_delete( 'shipment-items-' . $shipment->get_id(), 'shipments' ); + wp_cache_delete( $shipment->get_id(), $this->meta_type . '_meta' ); + wp_cache_delete( 'available-packaging-' . $shipment->get_id(), 'shipments' ); + } + + /* + |-------------------------------------------------------------------------- + | Additional Methods + |-------------------------------------------------------------------------- + */ + + /** + * @param \Vendidero\Germanized\Shipments\Shipment $shipment + */ + protected function get_search_index( $shipment ) { + $index = array(); + + if ( is_a( $shipment, '\Vendidero\Germanized\Shipments\ReturnShipment' ) ) { + $index = array_merge( $index, $shipment->get_sender_address() ); + } else { + $index = array_merge( $index, $shipment->get_address() ); + } + + return implode( ' ', $index ); + } + + protected function get_hook_postfix( $shipment ) { + if ( 'simple' !== $shipment->get_type() ) { + return $shipment->get_type() . '_'; + } + + return ''; + } + + /** + * Get the label type based on label ID. + * + * @param int $shipment_id Shipment id. + * @return string + */ + public function get_shipment_type( $shipment_id ) { + global $wpdb; + + $type = $wpdb->get_col( + $wpdb->prepare( + "SELECT shipment_type FROM {$wpdb->gzd_shipments} WHERE shipment_id = %d LIMIT 1", + $shipment_id + ) + ); + + return ! empty( $type ) ? $type[0] : false; + } + + /** + * Read extra data associated with the shipment. + * + * @param \Vendidero\Germanized\Shipments\Shipment $shipment Shipment object. + * @since 3.0.0 + */ + protected function read_shipment_data( &$shipment ) { + $props = array(); + + foreach ( $this->internal_meta_keys as $meta_key ) { + $props[ substr( $meta_key, 1 ) ] = get_metadata( 'gzd_shipment', $shipment->get_id(), $meta_key, true ); + } + + $shipment->set_props( $props ); + } + + /** + * @param \Vendidero\Germanized\Shipments\Shipment $shipment + */ + protected function save_shipment_data( &$shipment ) { + $updated_props = array(); + $meta_key_to_props = array(); + + foreach ( $this->internal_meta_keys as $meta_key ) { + $prop_name = substr( $meta_key, 1 ); + + if ( in_array( $prop_name, $this->core_props, true ) ) { + continue; + } + + $meta_key_to_props[ $meta_key ] = $prop_name; + } + + $props_to_update = $this->get_props_to_update( $shipment, $meta_key_to_props, 'gzd_shipment' ); + + foreach ( $props_to_update as $meta_key => $prop ) { + + if ( ! is_callable( array( $shipment, "get_$prop" ) ) ) { + continue; + } + + $value = $shipment->{"get_$prop"}( 'edit' ); + $value = is_string( $value ) ? wp_slash( $value ) : $value; + + switch ( $prop ) { + case 'is_customer_requested': + $value = wc_bool_to_string( $value ); + break; + } + + // Force updating props that are dependent on inner content data (weight, dimensions) + if ( in_array( $prop, array( 'weight', 'width', 'length', 'height' ), true ) && ! $shipment->is_editable() ) { + + // Get weight in view context to maybe allow calculating inner content props. + $value = $shipment->{"get_$prop"}( 'view' ); + $updated = update_metadata( 'gzd_shipment', $shipment->get_id(), $meta_key, $value ); + } else { + $updated = $this->update_or_delete_meta( $shipment, $meta_key, $value ); + } + + if ( $updated ) { + $updated_props[] = $prop; + } + } + + /** + * Action that fires after updating a Shipment's properties. + * + * @param \Vendidero\Germanized\Shipments\Shipment $shipment The shipment object. + * @param array $changed_props The updated properties. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_shipment_object_updated_props', $shipment, $updated_props ); + } + + /** + * Update meta data in, or delete it from, the database. + * + * Avoids storing meta when it's either an empty string or empty array. + * Other empty values such as numeric 0 and null should still be stored. + * Data-stores can force meta to exist using `must_exist_meta_keys`. + * + * Note: WordPress `get_metadata` function returns an empty string when meta data does not exist. + * + * @param WC_Data $object The WP_Data object (WC_Coupon for coupons, etc). + * @param string $meta_key Meta key to update. + * @param mixed $meta_value Value to save. + * + * @since 3.6.0 Added to prevent empty meta being stored unless required. + * + * @return bool True if updated/deleted. + */ + protected function update_or_delete_meta( $object, $meta_key, $meta_value ) { + if ( in_array( $meta_value, array( array(), '' ), true ) && ! in_array( $meta_key, $this->must_exist_meta_keys, true ) ) { + $updated = delete_metadata( 'gzd_shipment', $object->get_id(), $meta_key ); + } else { + $updated = update_metadata( 'gzd_shipment', $object->get_id(), $meta_key, $meta_value ); + } + + return (bool) $updated; + } + + /** + * Read items from the database for this shipment. + * + * @param \Vendidero\Germanized\Shipments\Shipment $shipment Shipment object. + * + * @return array + */ + public function read_items( $shipment ) { + global $wpdb; + + // Get from cache if available. + $items = 0 < $shipment->get_id() ? wp_cache_get( 'shipment-items-' . $shipment->get_id(), 'shipments' ) : false; + + if ( false === $items ) { + + $items = $wpdb->get_results( + $wpdb->prepare( "SELECT * FROM {$wpdb->gzd_shipment_items} WHERE shipment_id = %d ORDER BY shipment_item_id;", $shipment->get_id() ) + ); + + foreach ( $items as $item ) { + wp_cache_set( 'item-' . $item->shipment_item_id, $item, 'shipment-items' ); + } + + if ( 0 < $shipment->get_id() ) { + wp_cache_set( 'shipment-items-' . $shipment->get_id(), $items, 'shipments' ); + } + } + + if ( ! empty( $items ) ) { + + $shipment_type = $shipment->get_type(); + + $items = array_map( + function( $item_id ) use ( $shipment_type ) { + return wc_gzd_get_shipment_item( $item_id, $shipment_type ); + }, + array_combine( wp_list_pluck( $items, 'shipment_item_id' ), $items ) + ); + } else { + $items = array(); + } + + return $items; + } + + /** + * Remove all items from the shipment. + * + * @param \Vendidero\Germanized\Shipments\Shipment $shipment Shipment object. + */ + public function delete_items( $shipment ) { + global $wpdb; + + $wpdb->query( $wpdb->prepare( "DELETE FROM itemmeta USING {$wpdb->gzd_shipment_itemmeta} itemmeta INNER JOIN {$wpdb->gzd_shipment_items} items WHERE itemmeta.gzd_shipment_item_id = items.shipment_item_id and items.shipment_id = %d", $shipment->get_id() ) ); + $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->gzd_shipment_items} WHERE shipment_id = %d", $shipment->get_id() ) ); + + $this->clear_caches( $shipment ); + } + + /** + * Get valid WP_Query args from a WC_Order_Query's query variables. + * + * @since 3.0.6 + * @param array $query_vars query vars from a WC_Order_Query. + * @return array + */ + protected function get_wp_query_args( $query_vars ) { + global $wpdb; + + // Add the 'wc-' prefix to status if needed. + if ( ! empty( $query_vars['status'] ) ) { + if ( is_array( $query_vars['status'] ) ) { + foreach ( $query_vars['status'] as &$status ) { + $status = wc_gzd_is_shipment_status( 'gzd-' . $status ) ? 'gzd-' . $status : $status; + } + } else { + $query_vars['status'] = wc_gzd_is_shipment_status( 'gzd-' . $query_vars['status'] ) ? 'gzd-' . $query_vars['status'] : $query_vars['status']; + } + } + + $wp_query_args = parent::get_wp_query_args( $query_vars ); + + // Force type to be existent + if ( isset( $query_vars['type'] ) ) { + $wp_query_args['type'] = $query_vars['type']; + } + + if ( ! isset( $wp_query_args['date_query'] ) ) { + $wp_query_args['date_query'] = array(); + } + + if ( ! isset( $wp_query_args['meta_query'] ) ) { + $wp_query_args['meta_query'] = array(); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query + } + + // Allow Woo to treat these props as date query compatible + $date_queries = array( + 'date_created', + 'date_sent', + 'est_delivery_date', + ); + + foreach ( $date_queries as $db_key ) { + if ( isset( $query_vars[ $db_key ] ) && '' !== $query_vars[ $db_key ] ) { + + // Remove any existing meta queries for the same keys to prevent conflicts. + $existing_queries = wp_list_pluck( $wp_query_args['meta_query'], 'key', true ); + $meta_query_index = array_search( $db_key, $existing_queries, true ); + + if ( false !== $meta_query_index ) { + unset( $wp_query_args['meta_query'][ $meta_query_index ] ); + } + + $date_query_args = $this->parse_date_for_wp_query( $query_vars[ $db_key ], 'post_date', array() ); + + /** + * Replace date query columns after Woo parsed dates. + * Include table name because otherwise WP_Date_Query won't accept our custom column. + */ + if ( isset( $date_query_args['date_query'] ) && ! empty( $date_query_args['date_query'] ) ) { + $date_query = $date_query_args['date_query'][0]; + + if ( 'post_date' === $date_query['column'] ) { + $date_query['column'] = $wpdb->gzd_shipments . '.shipment_' . $db_key; + } + + $wp_query_args['date_query'][] = $date_query; + } + } + } + + if ( ! isset( $query_vars['paginate'] ) || ! $query_vars['paginate'] ) { + $wp_query_args['no_found_rows'] = true; + } + + /** + * Filter to adjust Shipments query arguments after parsing. + * + * @param array $wp_query_args Array containing parsed query arguments. + * @param array $query_vars The original query arguments. + * @param Shipment $data_store The shipment data store object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipping_data_store_get_shipments_query', $wp_query_args, $query_vars, $this ); + } + + /** + * Table structure is slightly different between meta types, this function will return what we need to know. + * + * @since 3.0.0 + * @return array Array elements: table, object_id_field, meta_id_field + */ + protected function get_db_info() { + global $wpdb; + + $meta_id_field = 'meta_id'; // for some reason users calls this umeta_id so we need to track this as well. + $table = $wpdb->gzd_shipmentmeta; + $object_id_field = $this->meta_type . '_id'; + + if ( ! empty( $this->object_id_field_for_meta ) ) { + $object_id_field = $this->object_id_field_for_meta; + } + + return array( + 'table' => $table, + 'object_id_field' => $object_id_field, + 'meta_id_field' => $meta_id_field, + ); + } + + public function get_query_args( $query_vars ) { + return $this->get_wp_query_args( $query_vars ); + } + + public function get_shipment_count( $status, $type = '' ) { + global $wpdb; + + if ( empty( $type ) ) { + $query = $wpdb->prepare( "SELECT COUNT( * ) FROM {$wpdb->gzd_shipments} WHERE shipment_status = %s", $status ); + } else { + $query = $wpdb->prepare( "SELECT COUNT( * ) FROM {$wpdb->gzd_shipments} WHERE shipment_status = %s and shipment_type = %s", $status, $type ); + } + + return absint( $wpdb->get_var( $query ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + } +} diff --git a/packages/woocommerce-germanized-shipments/src/DataStores/ShipmentItem.php b/packages/woocommerce-germanized-shipments/src/DataStores/ShipmentItem.php new file mode 100644 index 000000000..bc1debefe --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/DataStores/ShipmentItem.php @@ -0,0 +1,354 @@ +insert( + $wpdb->gzd_shipment_items, + array( + 'shipment_id' => $item->get_shipment_id(), + 'shipment_item_quantity' => $item->get_quantity(), + 'shipment_item_order_item_id' => $item->get_order_item_id(), + 'shipment_item_product_id' => $item->get_product_id(), + 'shipment_item_parent_id' => $item->get_parent_id(), + 'shipment_item_name' => $item->get_name(), + ) + ); + + $item->set_id( $wpdb->insert_id ); + $this->save_item_data( $item ); + $item->save_meta_data(); + $item->apply_changes(); + $this->clear_cache( $item ); + + /** + * Action that indicates that a new ShipmentItem has been created in the DB. + * + * @param integer $shipment_item_id The shipment item id. + * @param \Vendidero\Germanized\Shipments\ShipmentItem $item The shipment item object. + * @param integer $shipment_id The shipment id. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_new_shipment_item', $item->get_id(), $item, $item->get_shipment_id() ); + } + + /** + * Update a shipment item in the database. + * + * @since 3.0.0 + * @param \Vendidero\Germanized\Shipments\ShipmentItem $item Shipment item object. + */ + public function update( &$item ) { + global $wpdb; + + $changes = $item->get_changes(); + + if ( array_intersect( $this->core_props, array_keys( $changes ) ) ) { + $wpdb->update( + $wpdb->gzd_shipment_items, + array( + 'shipment_id' => $item->get_shipment_id(), + 'shipment_item_order_item_id' => $item->get_order_item_id(), + 'shipment_item_quantity' => $item->get_quantity(), + 'shipment_item_product_id' => $item->get_product_id(), + 'shipment_item_parent_id' => $item->get_parent_id(), + 'shipment_item_name' => $item->get_name(), + ), + array( 'shipment_item_id' => $item->get_id() ) + ); + } + + $this->save_item_data( $item ); + $item->save_meta_data(); + $item->apply_changes(); + $this->clear_cache( $item ); + + /** + * Action that indicates that a ShipmentItem has been updated in the DB. + * + * @param integer $shipment_item_id The shipment item id. + * @param \Vendidero\Germanized\Shipments\ShipmentItem $item The shipment item object. + * @param integer $shipment_id The shipment id. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_shipment_item_updated', $item->get_id(), $item, $item->get_shipment_id() ); + } + + /** + * Remove a shipment item from the database. + * + * @since 3.0.0 + * @param \Vendidero\Germanized\Shipments\ShipmentItem $item Shipment item object. + * @param array $args Array of args to pass to the delete method. + */ + public function delete( &$item, $args = array() ) { + if ( $item->get_id() ) { + global $wpdb; + + /** + * Action that fires before deleting a ShipmentItem from the DB. + * + * @param integer $shipment_item_id The shipment item id. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_before_delete_shipment_item', $item->get_id() ); + + $wpdb->delete( $wpdb->gzd_shipment_items, array( 'shipment_item_id' => $item->get_id() ) ); + $wpdb->delete( $wpdb->gzd_shipment_itemmeta, array( 'gzd_shipment_item_id' => $item->get_id() ) ); + + /** + * Action that indicates that a ShipmentItem has been deleted from the DB. + * + * @param integer $shipment_item_id The shipment item id. + * @param \Vendidero\Germanized\Shipments\ShipmentItem $item The shipment item object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_delete_shipment_item', $item->get_id(), $item ); + $this->clear_cache( $item ); + } + } + + /** + * Read a shipment item from the database. + * + * @since 3.0.0 + * + * @param \Vendidero\Germanized\Shipments\ShipmentItem $item Shipment item object. + * + * @throws Exception If invalid shipment item. + */ + public function read( &$item ) { + global $wpdb; + + $item->set_defaults(); + + // Get from cache if available. + $data = wp_cache_get( 'item-' . $item->get_id(), 'shipment-items' ); + + if ( false === $data ) { + $data = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->gzd_shipment_items} WHERE shipment_item_id = %d LIMIT 1;", $item->get_id() ) ); + wp_cache_set( 'item-' . $item->get_id(), $data, 'shipment-items' ); + } + + if ( ! $data ) { + throw new Exception( _x( 'Invalid shipment item.', 'shipments', 'woocommerce-germanized' ) ); + } + + $item->set_props( + array( + 'shipment_id' => $data->shipment_id, + 'order_item_id' => $data->shipment_item_order_item_id, + 'quantity' => $data->shipment_item_quantity, + 'product_id' => $data->shipment_item_product_id, + 'parent_id' => $data->shipment_item_parent_id, + 'name' => $data->shipment_item_name, + ) + ); + + $this->read_item_data( $item ); + $item->read_meta_data(); + $item->set_object_read( true ); + } + + /** + * Read extra data associated with the shipment item. + * + * @param \Vendidero\Germanized\Shipments\ShipmentItem $item Shipment item object. + * @since 3.0.0 + */ + protected function read_item_data( &$item ) { + $props = array(); + + foreach ( $this->internal_meta_keys as $meta_key ) { + $props[ substr( $meta_key, 1 ) ] = get_metadata( $this->meta_type, $item->get_id(), $meta_key, true ); + } + + $item->set_props( $props ); + } + + /** + * Update meta data in, or delete it from, the database. + * + * Avoids storing meta when it's either an empty string or empty array. + * Other empty values such as numeric 0 and null should still be stored. + * Data-stores can force meta to exist using `must_exist_meta_keys`. + * + * Note: WordPress `get_metadata` function returns an empty string when meta data does not exist. + * + * @param WC_Data $object The WP_Data object (WC_Coupon for coupons, etc). + * @param string $meta_key Meta key to update. + * @param mixed $meta_value Value to save. + * + * @since 3.6.0 Added to prevent empty meta being stored unless required. + * + * @return bool True if updated/deleted. + */ + protected function update_or_delete_meta( $object, $meta_key, $meta_value ) { + if ( in_array( $meta_value, array( array(), '' ), true ) && ! in_array( $meta_key, $this->must_exist_meta_keys, true ) ) { + $updated = delete_metadata( $this->meta_type, $object->get_id(), $meta_key ); + } else { + $updated = update_metadata( $this->meta_type, $object->get_id(), $meta_key, $meta_value ); + } + + return (bool) $updated; + } + + /** + * Saves an item's data to the database / item meta. + * Ran after both create and update, so $item->get_id() will be set. + * + * @since 3.0.0 + * @param \Vendidero\Germanized\Shipments\ShipmentItem $item Shipment item object. + */ + public function save_item_data( &$item ) { + $updated_props = array(); + $meta_key_to_props = array(); + + foreach ( $this->internal_meta_keys as $meta_key ) { + + $prop_name = substr( $meta_key, 1 ); + + if ( in_array( $prop_name, $this->core_props, true ) ) { + continue; + } + + $meta_key_to_props[ $meta_key ] = $prop_name; + } + + $props_to_update = $this->get_props_to_update( $item, $meta_key_to_props, $this->meta_type ); + + foreach ( $props_to_update as $meta_key => $prop ) { + + $getter = "get_$prop"; + + if ( ! is_callable( array( $item, $getter ) ) ) { + continue; + } + + $value = $item->{"get_$prop"}( 'edit' ); + $value = is_string( $value ) ? wp_slash( $value ) : $value; + + $updated = $this->update_or_delete_meta( $item, $meta_key, $value ); + + if ( $updated ) { + $updated_props[] = $prop; + } + } + + /** + * Action that fires after updating a ShipmentItem's properties. + * + * @param \Vendidero\Germanized\Shipments\ShipmentItem $item The shipment item object. + * @param array $changed_props The updated properties. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_shipment_item_object_updated_props', $item, $updated_props ); + } + + /** + * Clear meta cache. + * + * @param \Vendidero\Germanized\Shipments\ShipmentItem $item Shipment item object. + */ + public function clear_cache( &$item ) { + wp_cache_delete( 'item-' . $item->get_id(), 'shipment-items' ); + wp_cache_delete( 'shipment-items-' . $item->get_shipment_id(), 'shipments' ); + wp_cache_delete( $item->get_id(), $this->meta_type . '_meta' ); + } + + /** + * Table structure is slightly different between meta types, this function will return what we need to know. + * + * @since 3.0.0 + * @return array Array elements: table, object_id_field, meta_id_field + */ + protected function get_db_info() { + global $wpdb; + + $meta_id_field = 'meta_id'; // for some reason users calls this umeta_id so we need to track this as well. + $table = $wpdb->gzd_shipment_itemmeta; + $object_id_field = $this->meta_type . '_id'; + + if ( ! empty( $this->object_id_field_for_meta ) ) { + $object_id_field = $this->object_id_field_for_meta; + } + + return array( + 'table' => $table, + 'object_id_field' => $object_id_field, + 'meta_id_field' => $meta_id_field, + ); + } +} diff --git a/packages/woocommerce-germanized-shipments/src/DataStores/ShippingProvider.php b/packages/woocommerce-germanized-shipments/src/DataStores/ShippingProvider.php new file mode 100644 index 000000000..7a9376c41 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/DataStores/ShippingProvider.php @@ -0,0 +1,478 @@ +set_name( $this->get_unqiue_name( $provider ) ); + + $data = array( + 'shipping_provider_activated' => $provider->is_activated() ? 1 : 0, + 'shipping_provider_name' => $provider->get_name( 'edit' ), + 'shipping_provider_title' => $provider->get_title( 'edit' ), + ); + + $wpdb->insert( + $wpdb->gzd_shipping_provider, + $data + ); + + $provider_id = $wpdb->insert_id; + + if ( $provider_id ) { + $provider->set_id( $provider_id ); + + $this->save_provider_data( $provider ); + + $provider->update_settings_with_defaults(); + $provider->save_meta_data(); + $provider->apply_changes(); + + $this->clear_caches( $provider ); + + /** + * Action that indicates that a new Shipping Provider has been created in the DB. + * + * @param integer $provider_id The provider id. + * @param \Vendidero\Germanized\Shipments\ShippingProvider\Simple $shipping_provider The shipping provider instance. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_new_shipping_provider', $provider_id, $provider ); + } + } + + /** + * Generate a unique name to save to the object. + * + * @since 3.6.0 + * @param \Vendidero\Germanized\Shipments\ShippingProvider\Simple $provider Shipping provider object. + * @return string + */ + protected function get_unqiue_name( $provider ) { + global $wpdb; + + $slug = sanitize_key( $provider->get_title() ); + + // Post slugs must be unique across all posts. + $check_sql = "SELECT shipping_provider_name FROM $wpdb->gzd_shipping_provider WHERE shipping_provider_name = %s AND shipping_provider_id != %d LIMIT 1"; + $provider_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $slug, $provider->get_id() ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + + if ( $provider_name_check || ( $this->is_manual_creation_request() && $this->is_reserved_name( $slug ) ) ) { + $suffix = 2; + do { + $alt_provider_name = _truncate_post_slug( $slug, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix"; + $provider_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $alt_provider_name, $provider->get_id() ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + $suffix++; + } while ( $provider_name_check || ( $this->is_manual_creation_request() && $this->is_reserved_name( $alt_provider_name ) ) ); + $slug = $alt_provider_name; + } + + return $slug; + } + + protected function is_manual_creation_request() { + return apply_filters( 'woocommerce_gzd_shipments_shipping_provider_is_manual_creation_request', false ); + } + + protected function is_reserved_name( $name ) { + $reserved_names = array( + 'dhl', + 'deutsche_post', + 'dpd', + 'gls', + 'ups', + 'hermes', + ); + + return apply_filters( 'woocommerce_gzd_shipments_shipping_provider_is_reserved_name', in_array( $name, $reserved_names, true ) ); + } + + /** + * Method to update a shipping provider in the database. + * + * @param \Vendidero\Germanized\Shipments\ShippingProvider\Simple $provider Shipping provider object. + */ + public function update( &$provider ) { + global $wpdb; + + $updated_props = array(); + $core_props = $this->core_props; + $changed_props = array_keys( $provider->get_changes() ); + $provider_data = array(); + + foreach ( $changed_props as $prop ) { + + if ( ! in_array( $prop, $core_props, true ) ) { + continue; + } + + switch ( $prop ) { + case 'activated': + $provider_data[ 'shipping_provider_' . $prop ] = $provider->is_activated() ? 1 : 0; + break; + default: + if ( is_callable( array( $provider, 'get_' . $prop ) ) ) { + $provider_data[ 'shipping_provider_' . $prop ] = $provider->{'get_' . $prop}( 'edit' ); + } + break; + } + } + + if ( ! empty( $provider_data ) ) { + $wpdb->update( + $wpdb->gzd_shipping_provider, + $provider_data, + array( 'shipping_provider_id' => $provider->get_id() ) + ); + } + + $this->save_provider_data( $provider ); + + $provider->save_meta_data(); + $provider->apply_changes(); + + $this->clear_caches( $provider ); + + /** + * Action that indicates that a shipping provider has been updated in the DB. + * + * @param integer $shipping_provider_id The shipping provider id. + * @param \Vendidero\Germanized\Shipments\ShippingProvider\Simple $shipping_provider The shipping provider instance. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_shipping_provider_updated', $provider->get_id(), $provider ); + } + + /** + * Remove a shipping provider from the database. + * + * @since 3.0.0 + * @param \Vendidero\Germanized\Shipments\ShippingProvider\Simple $provider Shipping provider object. + * @param bool $force_delete Unused param. + */ + public function delete( &$provider, $force_delete = false ) { + global $wpdb; + + $wpdb->delete( $wpdb->gzd_shipping_provider, array( 'shipping_provider_id' => $provider->get_id() ), array( '%d' ) ); + $wpdb->delete( $wpdb->gzd_shipping_providermeta, array( 'gzd_shipping_provider_id' => $provider->get_id() ), array( '%d' ) ); + + $this->clear_caches( $provider ); + + /** + * Action that indicates that a shipping provider has been deleted from the DB. + * + * @param integer $shipping_provider_id The shipping provider id. + * @param \Vendidero\Germanized\Shipments\ShippingProvider\Simple $provider The shipping provider object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_shipping_provider_deleted', $provider->get_id(), $provider ); + } + + /** + * Read a shipping provider from the database. + * + * @since 3.0.0 + * + * @param \Vendidero\Germanized\Shipments\ShippingProvider\Simple $provider Shipping provider object. + * + * @throws Exception Throw exception if invalid shipping provider. + */ + public function read( &$provider ) { + global $wpdb; + + $data = $wpdb->get_row( + $wpdb->prepare( + "SELECT * FROM {$wpdb->gzd_shipping_provider} WHERE shipping_provider_id = %d LIMIT 1", + $provider->get_id() + ) + ); + + if ( $data ) { + $provider->set_props( + array( + 'name' => $data->shipping_provider_name, + 'title' => $data->shipping_provider_title, + 'activated' => $data->shipping_provider_activated, + ) + ); + + $this->read_provider_data( $provider ); + + $provider->read_meta_data(); + $provider->set_object_read( true ); + + /** + * Action that indicates that a shipping provider has been loaded from DB. + * + * @param \Vendidero\Germanized\Shipments\ShippingProvider\Simple $provider The shipping provider object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_shipping_provider_loaded', $provider ); + } else { + throw new Exception( _x( 'Invalid shipping provider.', 'shipments', 'woocommerce-germanized' ) ); + } + } + + public function is_activated( $name ) { + global $wpdb; + + $data = $wpdb->get_row( + $wpdb->prepare( + "SELECT shipping_provider_activated FROM {$wpdb->gzd_shipping_provider} WHERE shipping_provider_name = %s LIMIT 1", + $name + ) + ); + + if ( $data ) { + return wc_string_to_bool( $data->shipping_provider_activated ); + } + + return false; + } + + /** + * Clear any caches. + * + * @param \Vendidero\Germanized\Shipments\ShippingProvider\Simple $provider Shipping provider object. + * @since 3.0.0 + */ + protected function clear_caches( &$provider ) { + wp_cache_delete( $provider->get_id(), $this->meta_type . '_meta' ); + } + + /* + |-------------------------------------------------------------------------- + | Additional Methods + |-------------------------------------------------------------------------- + */ + + /** + * Read extra data associated with the shipping provider. + * + * @param \Vendidero\Germanized\Shipments\ShippingProvider\Simple $provider Shipping provider object. + * @since 3.0.0 + */ + protected function read_provider_data( &$provider ) { + $props = array(); + $meta_keys = $this->internal_meta_keys; + + foreach ( $provider->get_extra_data_keys() as $key ) { + $meta_keys[] = '_' . $key; + } + + foreach ( $meta_keys as $meta_key ) { + $props[ substr( $meta_key, 1 ) ] = get_metadata( 'gzd_shipping_provider', $provider->get_id(), $meta_key, true ); + } + + $provider->set_props( $props ); + } + + /** + * Save shipping provider data. + * + * @param \Vendidero\Germanized\Shipments\ShippingProvider\Simple $provider Shipping provider object. + */ + protected function save_provider_data( &$provider ) { + $updated_props = array(); + $meta_key_to_props = array(); + + foreach ( $this->internal_meta_keys as $meta_key ) { + $prop_name = substr( $meta_key, 1 ); + + if ( in_array( $prop_name, $this->core_props, true ) ) { + continue; + } + + $meta_key_to_props[ $meta_key ] = $prop_name; + } + + // Make sure to take extra data (like product url or text for external products) into account. + $extra_data_keys = $provider->get_extra_data_keys(); + + foreach ( $extra_data_keys as $key ) { + $meta_key_to_props[ '_' . $key ] = $key; + } + + $props_to_update = $this->get_props_to_update( $provider, $meta_key_to_props, 'gzd_shipping_provider' ); + + foreach ( $props_to_update as $meta_key => $prop ) { + + if ( ! is_callable( array( $provider, "get_$prop" ) ) ) { + continue; + } + + $value = $provider->{"get_$prop"}( 'edit' ); + $value = is_string( $value ) ? wp_slash( $value ) : $value; + + if ( is_bool( $value ) ) { + $value = wc_bool_to_string( $value ); + } + + $updated = $this->update_or_delete_meta( $provider, $meta_key, $value ); + + if ( $updated ) { + $updated_props[] = $prop; + } + } + + /** + * Action that fires after updating a shipping providers' properties. + * + * @param \Vendidero\Germanized\Shipments\ShippingProvider\Simple $provider The shipping provider object. + * @param array $changed_props The updated properties. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_shipping_provider_object_updated_props', $provider, $updated_props ); + } + + /** + * Update meta data in, or delete it from, the database. + * + * Avoids storing meta when it's either an empty string or empty array. + * Other empty values such as numeric 0 and null should still be stored. + * Data-stores can force meta to exist using `must_exist_meta_keys`. + * + * Note: WordPress `get_metadata` function returns an empty string when meta data does not exist. + * + * @param WC_Data $object The WP_Data object (WC_Coupon for coupons, etc). + * @param string $meta_key Meta key to update. + * @param mixed $meta_value Value to save. + * + * @since 3.6.0 Added to prevent empty meta being stored unless required. + * + * @return bool True if updated/deleted. + */ + protected function update_or_delete_meta( $object, $meta_key, $meta_value ) { + if ( in_array( $meta_value, array( array(), '' ), true ) && ! in_array( $meta_key, $this->must_exist_meta_keys, true ) ) { + $updated = delete_metadata( 'gzd_shipping_provider', $object->get_id(), $meta_key ); + } else { + $updated = update_metadata( 'gzd_shipping_provider', $object->get_id(), $meta_key, $meta_value ); + } + + return (bool) $updated; + } + + /** + * Table structure is slightly different between meta types, this function will return what we need to know. + * + * @since 3.0.0 + * @return array Array elements: table, object_id_field, meta_id_field + */ + protected function get_db_info() { + global $wpdb; + + $meta_id_field = 'meta_id'; // for some reason users calls this umeta_id so we need to track this as well. + $table = $wpdb->gzd_shipping_providermeta; + $object_id_field = $this->meta_type . '_id'; + + if ( ! empty( $this->object_id_field_for_meta ) ) { + $object_id_field = $this->object_id_field_for_meta; + } + + return array( + 'table' => $table, + 'object_id_field' => $object_id_field, + 'meta_id_field' => $meta_id_field, + ); + } + + public function get_shipping_provider_count() { + global $wpdb; + + return absint( $wpdb->get_var( "SELECT COUNT( * ) FROM {$wpdb->gzd_shipping_provider}" ) ); + } + + public function get_shipping_provider_name( $provider_id ) { + global $wpdb; + + $provider_name_check = $wpdb->get_row( $wpdb->prepare( "SELECT shipping_provider_name FROM $wpdb->gzd_shipping_provider WHERE shipping_provider_id = %d LIMIT 1", $provider_id ) ); + + if ( ! empty( $provider_name_check ) ) { + return $provider_name_check->shipping_provider_name; + } + + return false; + } + + public function get_shipping_providers() { + global $wpdb; + + $providers = $wpdb->get_results( "SELECT * FROM $wpdb->gzd_shipping_provider" ); + $shipping_providers = array(); + + foreach ( $providers as $provider ) { + try { + $shipping_providers[ $provider->shipping_provider_name ] = $provider; + } catch ( Exception $e ) { + continue; + } + } + + return $shipping_providers; + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Emails.php b/packages/woocommerce-germanized-shipments/src/Emails.php new file mode 100644 index 000000000..a0c772f1c --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Emails.php @@ -0,0 +1,232 @@ +id ), $email ) ) ) { + if ( $shipments_order = wc_gzd_get_shipment_order( $order ) ) { + $template = $plain_text ? 'plain/email-order-shipments.php' : 'email-order-shipments.php'; + + wc_get_template( + 'emails/' . $template, + array( + 'shipments' => $shipments_order->get_simple_shipments( true ), + 'sent_to_admin' => $sent_to_admin, + 'plain_text' => $plain_text, + 'email' => $email, + ) + ); + } + } + } + + public static function set_woocommerce_template_dir( $dir, $template ) { + if ( file_exists( Package::get_path() . '/templates/' . $template ) ) { + return 'woocommerce-germanized'; + } + + return $dir; + } + + public static function register_emails( $emails ) { + $emails['WC_GZD_Email_Customer_Shipment'] = include Package::get_path() . '/includes/emails/class-wc-gzd-email-customer-shipment.php'; + $emails['WC_GZD_Email_Customer_Return_Shipment'] = include Package::get_path() . '/includes/emails/class-wc-gzd-email-customer-return-shipment.php'; + $emails['WC_GZD_Email_Customer_Return_Shipment_Delivered'] = include Package::get_path() . '/includes/emails/class-wc-gzd-email-customer-return-shipment-delivered.php'; + $emails['WC_GZD_Email_Customer_Guest_Return_Shipment_Request'] = include Package::get_path() . '/includes/emails/class-wc-gzd-email-customer-guest-return-shipment-request.php'; + $emails['WC_GZD_Email_New_Return_Shipment_Request'] = include Package::get_path() . '/includes/emails/class-wc-gzd-email-new-return-shipment-request.php'; + + return $emails; + } + + public static function email_hooks() { + add_action( 'woocommerce_gzd_email_shipment_details', array( __CLASS__, 'email_return_instructions' ), 5, 4 ); + add_action( 'woocommerce_gzd_email_shipment_details', array( __CLASS__, 'email_tracking' ), 10, 4 ); + add_action( 'woocommerce_gzd_email_shipment_details', array( __CLASS__, 'email_address' ), 20, 4 ); + add_action( 'woocommerce_gzd_email_shipment_details', array( __CLASS__, 'email_details' ), 30, 4 ); + } + + public static function register_email_notifications( $actions ) { + + $actions = array_merge( + $actions, + array( + 'woocommerce_gzd_shipment_status_draft_to_processing', + 'woocommerce_gzd_shipment_status_draft_to_shipped', + 'woocommerce_gzd_shipment_status_draft_to_delivered', + 'woocommerce_gzd_shipment_status_processing_to_shipped', + 'woocommerce_gzd_shipment_status_processing_to_delivered', + 'woocommerce_gzd_shipment_status_shipped_to_delivered', + 'woocommerce_gzd_return_shipment_status_draft_to_processing', + 'woocommerce_gzd_return_shipment_status_draft_to_shipped', + 'woocommerce_gzd_return_shipment_status_draft_to_delivered', + 'woocommerce_gzd_return_shipment_status_draft_to_requested', + 'woocommerce_gzd_return_shipment_status_processing_to_shipped', + 'woocommerce_gzd_return_shipment_status_processing_to_delivered', + 'woocommerce_gzd_return_shipment_status_shipped_to_delivered', + 'woocommerce_gzd_return_shipment_status_requested_to_processing', + 'woocommerce_gzd_return_shipment_status_requested_to_shipped', + ) + ); + + return $actions; + } + + /** + * @param Shipment $shipment + * @param bool $sent_to_admin + * @param bool $plain_text + * @param string $email + */ + public static function email_return_instructions( $shipment, $sent_to_admin = false, $plain_text = false, $email = '' ) { + + if ( 'return' !== $shipment->get_type() || $shipment->has_status( 'delivered' ) ) { + return; + } + + if ( $plain_text ) { + wc_get_template( + 'emails/plain/email-return-shipment-instructions.php', + array( + 'shipment' => $shipment, + 'sent_to_admin' => $sent_to_admin, + 'plain_text' => $plain_text, + 'email' => $email, + ) + ); + } else { + wc_get_template( + 'emails/email-return-shipment-instructions.php', + array( + 'shipment' => $shipment, + 'sent_to_admin' => $sent_to_admin, + 'plain_text' => $plain_text, + 'email' => $email, + ) + ); + } + } + + /** + * @param Shipment $shipment + * @param bool $sent_to_admin + * @param bool $plain_text + * @param string $email + */ + public static function email_tracking( $shipment, $sent_to_admin = false, $plain_text = false, $email = '' ) { + + // Do only include shipment tracking if estimated delivery date or tracking instruction or tracking url exists + // Do not show tracking for returns + if ( ! $shipment->has_tracking() || $shipment->has_status( 'delivered' ) || 'return' === $shipment->get_type() ) { + return; + } + + if ( $plain_text ) { + wc_get_template( + 'emails/plain/email-shipment-tracking.php', + array( + 'shipment' => $shipment, + 'sent_to_admin' => $sent_to_admin, + 'plain_text' => $plain_text, + 'email' => $email, + ) + ); + } else { + wc_get_template( + 'emails/email-shipment-tracking.php', + array( + 'shipment' => $shipment, + 'sent_to_admin' => $sent_to_admin, + 'plain_text' => $plain_text, + 'email' => $email, + ) + ); + } + } + + /** + * @param Shipment $shipment + * @param bool $sent_to_admin + * @param bool $plain_text + * @param string $email + */ + public static function email_address( $shipment, $sent_to_admin = false, $plain_text = false, $email = '' ) { + if ( 'return' === $shipment->get_type() || in_array( $email, array( 'customer_return_shipment_delivered' ), true ) ) { + if ( $provider = $shipment->get_shipping_provider_instance() ) { + if ( $provider->hide_return_address() ) { + return; + } + } + } + + if ( $plain_text ) { + wc_get_template( + 'emails/plain/email-shipment-address.php', + array( + 'shipment' => $shipment, + 'sent_to_admin' => $sent_to_admin, + 'plain_text' => $plain_text, + 'email' => $email, + ) + ); + } else { + wc_get_template( + 'emails/email-shipment-address.php', + array( + 'shipment' => $shipment, + 'sent_to_admin' => $sent_to_admin, + 'plain_text' => $plain_text, + 'email' => $email, + ) + ); + } + } + + /** + * Show the order details table + * + * @param \WC_Order $order Order instance. + * @param bool $sent_to_admin If should sent to admin. + * @param bool $plain_text If is plain text email. + * @param string $email Email address. + */ + public static function email_details( $shipment, $sent_to_admin = false, $plain_text = false, $email = '' ) { + if ( $plain_text ) { + wc_get_template( + 'emails/plain/email-shipment-details.php', + array( + 'shipment' => $shipment, + 'sent_to_admin' => $sent_to_admin, + 'plain_text' => $plain_text, + 'email' => $email, + ) + ); + } else { + wc_get_template( + 'emails/email-shipment-details.php', + array( + 'shipment' => $shipment, + 'sent_to_admin' => $sent_to_admin, + 'plain_text' => $plain_text, + 'email' => $email, + ) + ); + } + } +} diff --git a/packages/woocommerce-germanized-shipments/src/FormHandler.php b/packages/woocommerce-germanized-shipments/src/FormHandler.php new file mode 100644 index 000000000..b51d6548d --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/FormHandler.php @@ -0,0 +1,325 @@ + $email, + 'post__in' => array( $order_id_parsed ), + 'limit' => 1, + 'return' => 'ids', + ) + ) + ); + + // Now lets try to find the order by a custom order number + if ( empty( $orders ) ) { + $orders = new WP_Query( + apply_filters( + 'woocommerce_gzd_return_request_order_query_args', + array( + 'post_type' => 'shop_order', + 'post_status' => 'any', + 'limit' => 1, + 'fields' => 'ids', + 'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query + 'relation' => 'AND', + array( + 'key' => '_billing_email', + 'value' => $email, + 'compare' => '=', + ), + array( + 'key' => apply_filters( 'woocommerce_gzd_return_request_customer_order_number_meta_key', '_order_number' ), + 'value' => $order_id, + 'compare' => '=', + ), + ), + ) + ) + ); + + if ( ! empty( $orders->posts ) ) { + $db_order_id = $orders->posts[0]; + } + } else { + $db_order_id = $orders[0]; + } + + if ( ! $db_order_id || ( ! $order = wc_get_order( $db_order_id ) ) ) { + throw new Exception( '' . _x( 'Error:', 'shipments', 'woocommerce-germanized' ) . ' ' . _x( 'We were not able to find a matching order.', 'shipments', 'woocommerce-germanized' ) ); + } + + if ( ! wc_gzd_order_is_customer_returnable( $order ) ) { + throw new Exception( '' . _x( 'Error:', 'shipments', 'woocommerce-germanized' ) . ' ' . _x( 'This order is currently not eligible for returns. Please contact us for further details.', 'shipments', 'woocommerce-germanized' ) ); + } + + $key = 'wc_gzd_order_return_request_' . wp_generate_password( 13, false ); + + $order->update_meta_data( '_return_request_key', $key ); + $order->save(); + + // Send email to customer + wc_add_notice( _x( 'Thank you. You\'ll receive an email containing a link to create a new return to your order.', 'shipments', 'woocommerce-germanized' ), 'success' ); + + WC()->mailer()->emails['WC_GZD_Email_Customer_Guest_Return_Shipment_Request']->trigger( $order ); + + do_action( 'woocommerce_gzd_return_request_successfull', $order ); + + } catch ( Exception $e ) { + wc_add_notice( $e->getMessage(), 'error' ); + do_action( 'woocommerce_gzd_return_request_failed' ); + } + } + } + + /** + * Save the password/account details and redirect back to the my account page. + */ + public static function add_return_shipment() { + $nonce_value = isset( $_REQUEST['add-return-shipment-nonce'] ) ? wp_unslash( $_REQUEST['add-return-shipment-nonce'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + + if ( ! wp_verify_nonce( $nonce_value, 'add_return_shipment' ) ) { + return; + } + + if ( empty( $_POST['action'] ) || 'gzd_add_return_shipment' !== $_POST['action'] ) { + return; + } + + wc_nocache_headers(); + + $order_id = ! empty( $_POST['order_id'] ) ? absint( wp_unslash( $_POST['order_id'] ) ) : false; + $items = ! empty( $_POST['items'] ) ? wc_clean( wp_unslash( $_POST['items'] ) ) : array(); + $item_data = ! empty( $_POST['item'] ) ? wc_clean( wp_unslash( $_POST['item'] ) ) : array(); + + if ( ! ( $order = wc_get_order( $order_id ) ) || ( ! wc_gzd_customer_can_add_return_shipment( $order_id ) ) ) { + wc_add_notice( _x( 'You are not allowed to add returns to that order.', 'shipments', 'woocommerce-germanized' ), 'error' ); + return; + } + + if ( ! wc_gzd_order_is_customer_returnable( $order ) ) { + wc_add_notice( _x( 'Sorry, but this order does not support returns any longer.', 'shipments', 'woocommerce-germanized' ), 'error' ); + return; + } + + if ( empty( $items ) ) { + wc_add_notice( _x( 'Please choose one or more items from the list.', 'shipments', 'woocommerce-germanized' ), 'error' ); + return; + } + + $return_items = array(); + $shipment_order = wc_gzd_get_shipment_order( $order ); + + foreach ( $items as $order_item_id ) { + + if ( $item = $shipment_order->get_simple_shipment_item( $order_item_id ) ) { + + $quantity = isset( $item_data[ $order_item_id ]['quantity'] ) ? absint( $item_data[ $order_item_id ]['quantity'] ) : 0; + $quantity_returnable = $shipment_order->get_item_quantity_left_for_returning( $order_item_id ); + $reason = isset( $item_data[ $order_item_id ]['reason'] ) ? wc_clean( $item_data[ $order_item_id ]['reason'] ) : ''; + + if ( ! empty( $reason ) && ! wc_gzd_return_shipment_reason_exists( $reason ) ) { + wc_add_notice( _x( 'The return reason you have chosen does not exist.', 'shipments', 'woocommerce-germanized' ), 'error' ); + return; + } elseif ( empty( $reason ) && ! wc_gzd_allow_customer_return_empty_return_reason( $order ) ) { + wc_add_notice( _x( 'Please choose a return reason from the list.', 'shipments', 'woocommerce-germanized' ), 'error' ); + return; + } + + if ( $quantity > $quantity_returnable ) { + wc_add_notice( _x( 'Please check your item quantities. Quantities must not exceed maximum quantities.', 'shipments', 'woocommerce-germanized' ), 'error' ); + return; + } else { + $return_items[ $order_item_id ] = array( + 'quantity' => $quantity, + 'return_reason_code' => $reason, + ); + } + } + } + + if ( empty( $return_items ) ) { + wc_add_notice( _x( 'Please choose one or more items from the list.', 'shipments', 'woocommerce-germanized' ), 'error' ); + } + + if ( wc_notice_count( 'error' ) > 0 ) { + return; + } + + $needs_manual_confirmation = wc_gzd_customer_return_needs_manual_confirmation( $order ); + + if ( $needs_manual_confirmation ) { + $default_status = 'requested'; + } else { + $default_status = 'processing'; + } + + // Add return shipment + $return_shipment = wc_gzd_create_return_shipment( + $shipment_order, + array( + 'items' => $return_items, + 'props' => array( + /** + * This filter may be used to adjust the default status of a return shipment + * added by a customer. + * + * @param string $status The default status. + * @param WC_Order $order The order object. + * + * @since 3.1.0 + * @package Vendidero/Germanized/Shipments + */ + 'status' => apply_filters( 'woocommerce_gzd_customer_new_return_shipment_request_status', $default_status, $order ), + 'is_customer_requested' => true, + ), + ) + ); + + if ( is_wp_error( $return_shipment ) ) { + wc_add_notice( _x( 'There was an error while creating the return. Please contact us for further information.', 'shipments', 'woocommerce-germanized' ), 'error' ); + return; + } else { + // Delete return request key if available + $shipment_order->delete_order_return_request_key(); + + $success_message = self::get_return_request_success_message( $needs_manual_confirmation ); + + // Do not add success message for guest returns + if ( $order->get_customer_id() > 0 ) { + wc_add_notice( $success_message ); + } + + /** + * This hook is fired after a customer has added a new return request + * for a specific shipment. The return shipment object has been added successfully. + * + * @param ReturnShipment $shipment The return shipment object. + * @param WC_Order $order The order object. + * + * @since 3.1.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_new_customer_return_shipment_request', $return_shipment, $order ); + + if ( $needs_manual_confirmation ) { + $return_url = $order->get_view_order_url(); + } else { + $return_url = $return_shipment->get_view_shipment_url(); + } + + if ( $order->get_customer_id() <= 0 ) { + $return_url = add_query_arg( + array( + 'return-request-success' => 'yes', + 'needs-confirmation' => wc_bool_to_string( $needs_manual_confirmation ), + ), + wc_get_page_permalink( 'myaccount' ) + ); + } + + /** + * This filter may be used to adjust the redirect of a customer + * after adding a new return shipment. In case the return request needs manual confirmation + * the customer will be redirected to the parent shipment. + * + * @param string $url The redirect URL. + * @param ReturnShipment $shipment The return shipment object. + * @param boolean $needs_manual_confirmation Whether the request needs manual confirmation or not. + * + * @since 3.1.0 + * @package Vendidero/Germanized/Shipments + */ + $redirect = apply_filters( 'woocommerce_gzd_customer_new_return_shipment_request_redirect', $return_url, $return_shipment, $needs_manual_confirmation ); + + wp_safe_redirect( esc_url_raw( $redirect ) ); + exit; + } + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Install.php b/packages/woocommerce-germanized-shipments/src/Install.php new file mode 100644 index 000000000..a8dc43ffe --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Install.php @@ -0,0 +1,322 @@ +get_shipping_providers(); + + foreach ( $providers as $provider ) { + if ( ! $provider->is_activated() ) { + continue; + } + + $provider->update_settings_with_defaults(); + $provider->save(); + } + } + + private static function maybe_create_return_reasons() { + $reasons = get_option( 'woocommerce_gzd_shipments_return_reasons', null ); + + if ( is_null( $reasons ) ) { + $default_reasons = array( + array( + 'order' => 1, + 'code' => 'wrong-product', + 'reason' => _x( 'Wrong product or size ordered', 'shipments', 'woocommerce-germanized' ), + ), + array( + 'order' => 2, + 'code' => 'not-needed', + 'reason' => _x( 'Product no longer needed', 'shipments', 'woocommerce-germanized' ), + ), + array( + 'order' => 3, + 'code' => 'look', + 'reason' => _x( 'Don\'t like the look', 'shipments', 'woocommerce-germanized' ), + ), + ); + + update_option( 'woocommerce_gzd_shipments_return_reasons', $default_reasons ); + } + } + + private static function get_db_version() { + return get_option( 'woocommerce_gzd_shipments_db_version', null ); + } + + private static function maybe_create_packaging() { + $packaging = wc_gzd_get_packaging_list(); + $db_version = self::get_db_version(); + + if ( empty( $packaging ) && is_null( $db_version ) ) { + $defaults = array( + array( + 'description' => _x( 'Cardboard S', 'shipments', 'woocommerce-germanized' ), + 'length' => 25, + 'width' => 17.5, + 'height' => 10, + 'weight' => 0.14, + 'max_content_weight' => 30, + 'type' => 'cardboard', + ), + array( + 'description' => _x( 'Cardboard M', 'shipments', 'woocommerce-germanized' ), + 'length' => 37.5, + 'width' => 30, + 'height' => 13.5, + 'weight' => 0.23, + 'max_content_weight' => 30, + 'type' => 'cardboard', + ), + array( + 'description' => _x( 'Cardboard L', 'shipments', 'woocommerce-germanized' ), + 'length' => 45, + 'width' => 35, + 'height' => 20, + 'weight' => 0.3, + 'max_content_weight' => 30, + 'type' => 'cardboard', + ), + array( + 'description' => _x( 'Letter C5/6', 'shipments', 'woocommerce-germanized' ), + 'length' => 22, + 'width' => 11, + 'height' => 1, + 'weight' => 0, + 'max_content_weight' => 0.05, + 'type' => 'letter', + ), + array( + 'description' => _x( 'Letter C4', 'shipments', 'woocommerce-germanized' ), + 'length' => 22.9, + 'width' => 32.4, + 'height' => 2, + 'weight' => 0.01, + 'max_content_weight' => 1, + 'type' => 'letter', + ), + ); + + foreach ( $defaults as $default ) { + $packaging = new Packaging(); + $packaging->set_props( $default ); + $packaging->save(); + } + } + } + + private static function create_tables() { + global $wpdb; + + $current_version = get_option( 'woocommerce_gzd_shipments_version', null ); + + /** + * Make possible duplicate names unique. + */ + if ( null !== $current_version && isset( $wpdb->gzd_shipping_provider ) ) { + $providers = $wpdb->get_results( "SELECT * FROM $wpdb->gzd_shipping_provider" ); + $shipping_providers = array(); + + foreach ( $providers as $provider ) { + if ( in_array( $provider->shipping_provider_name, $shipping_providers, true ) ) { + $unique_provider_name = sanitize_title( $provider->shipping_provider_name . '_' . wp_generate_password( 4, false, false ) ); + + $wpdb->update( + $wpdb->gzd_shipping_provider, + array( + 'shipping_provider_name' => $unique_provider_name, + ), + array( 'shipping_provider_id' => $provider->shipping_provider_id ) + ); + } else { + $shipping_providers[] = $provider->shipping_provider_name; + } + } + } + + $wpdb->hide_errors(); + require_once ABSPATH . 'wp-admin/includes/upgrade.php'; + dbDelta( self::get_schema() ); + } + + private static function create_upload_dir() { + Package::maybe_set_upload_dir(); + + $dir = Package::get_upload_dir(); + + if ( ! @is_dir( $dir['basedir'] ) ) { // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged + @mkdir( $dir['basedir'] ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged + } + + if ( ! file_exists( trailingslashit( $dir['basedir'] ) . '.htaccess' ) ) { + @file_put_contents( trailingslashit( $dir['basedir'] ) . '.htaccess', 'deny from all' ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged,WordPress.WP.AlternativeFunctions.file_system_read_file_put_contents + } + + if ( ! file_exists( trailingslashit( $dir['basedir'] ) . 'index.php' ) ) { + @touch( trailingslashit( $dir['basedir'] ) . 'index.php' ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged + } + } + + private static function get_schema() { + global $wpdb; + + $collate = ''; + + if ( $wpdb->has_cap( 'collation' ) ) { + $collate = $wpdb->get_charset_collate(); + } + + /** + * Use a varchar(191) for shipping_provider_name as the key length might overflow max key length for older MySQL (< 5.7). + * @see https://stackoverflow.com/a/31474509 + */ + $tables = " +CREATE TABLE {$wpdb->prefix}woocommerce_gzd_shipment_items ( + shipment_item_id BIGINT UNSIGNED NOT NULL auto_increment, + shipment_id BIGINT UNSIGNED NOT NULL, + shipment_item_name TEXT NOT NULL, + shipment_item_order_item_id BIGINT UNSIGNED NOT NULL, + shipment_item_product_id BIGINT UNSIGNED NOT NULL, + shipment_item_parent_id BIGINT UNSIGNED NOT NULL, + shipment_item_quantity SMALLINT UNSIGNED NOT NULL DEFAULT '1', + PRIMARY KEY (shipment_item_id), + KEY shipment_id (shipment_id), + KEY shipment_item_order_item_id (shipment_item_order_item_id), + KEY shipment_item_product_id (shipment_item_product_id), + KEY shipment_item_parent_id (shipment_item_parent_id) +) $collate; +CREATE TABLE {$wpdb->prefix}woocommerce_gzd_shipment_itemmeta ( + meta_id BIGINT UNSIGNED NOT NULL auto_increment, + gzd_shipment_item_id BIGINT UNSIGNED NOT NULL, + meta_key varchar(255) default NULL, + meta_value longtext NULL, + PRIMARY KEY (meta_id), + KEY gzd_shipment_item_id (gzd_shipment_item_id), + KEY meta_key (meta_key(32)) +) $collate; +CREATE TABLE {$wpdb->prefix}woocommerce_gzd_shipments ( + shipment_id BIGINT UNSIGNED NOT NULL auto_increment, + shipment_date_created datetime NOT NULL default '0000-00-00 00:00:00', + shipment_date_created_gmt datetime NOT NULL default '0000-00-00 00:00:00', + shipment_date_sent datetime NOT NULL default '0000-00-00 00:00:00', + shipment_date_sent_gmt datetime NOT NULL default '0000-00-00 00:00:00', + shipment_est_delivery_date datetime NOT NULL default '0000-00-00 00:00:00', + shipment_est_delivery_date_gmt datetime NOT NULL default '0000-00-00 00:00:00', + shipment_status varchar(20) NOT NULL default 'gzd-draft', + shipment_order_id BIGINT UNSIGNED NOT NULL DEFAULT 0, + shipment_packaging_id BIGINT UNSIGNED NOT NULL DEFAULT 0, + shipment_parent_id BIGINT UNSIGNED NOT NULL DEFAULT 0, + shipment_country varchar(2) NOT NULL DEFAULT '', + shipment_tracking_id varchar(200) NOT NULL DEFAULT '', + shipment_type varchar(200) NOT NULL DEFAULT '', + shipment_version varchar(200) NOT NULL DEFAULT '', + shipment_search_index longtext NOT NULL DEFAULT '', + shipment_shipping_provider varchar(200) NOT NULL DEFAULT '', + shipment_shipping_method varchar(200) NOT NULL DEFAULT '', + PRIMARY KEY (shipment_id), + KEY shipment_order_id (shipment_order_id), + KEY shipment_packaging_id (shipment_packaging_id), + KEY shipment_parent_id (shipment_parent_id) +) $collate; +CREATE TABLE {$wpdb->prefix}woocommerce_gzd_shipment_labels ( + label_id BIGINT UNSIGNED NOT NULL auto_increment, + label_date_created datetime NOT NULL default '0000-00-00 00:00:00', + label_date_created_gmt datetime NOT NULL default '0000-00-00 00:00:00', + label_shipment_id BIGINT UNSIGNED NOT NULL, + label_parent_id BIGINT UNSIGNED NOT NULL DEFAULT 0, + label_number varchar(200) NOT NULL DEFAULT '', + label_product_id varchar(200) NOT NULL DEFAULT '', + label_shipping_provider varchar(200) NOT NULL DEFAULT '', + label_path varchar(200) NOT NULL DEFAULT '', + label_type varchar(200) NOT NULL DEFAULT '', + PRIMARY KEY (label_id), + KEY label_shipment_id (label_shipment_id), + KEY label_parent_id (label_parent_id) +) $collate; +CREATE TABLE {$wpdb->prefix}woocommerce_gzd_shipment_labelmeta ( + meta_id BIGINT UNSIGNED NOT NULL auto_increment, + gzd_shipment_label_id BIGINT UNSIGNED NOT NULL, + meta_key varchar(255) default NULL, + meta_value longtext NULL, + PRIMARY KEY (meta_id), + KEY gzd_shipment_label_id (gzd_shipment_label_id), + KEY meta_key (meta_key(32)) +) $collate; +CREATE TABLE {$wpdb->prefix}woocommerce_gzd_shipmentmeta ( + meta_id BIGINT UNSIGNED NOT NULL auto_increment, + gzd_shipment_id BIGINT UNSIGNED NOT NULL, + meta_key varchar(255) default NULL, + meta_value longtext NULL, + PRIMARY KEY (meta_id), + KEY gzd_shipment_id (gzd_shipment_id), + KEY meta_key (meta_key(32)) +) $collate; +CREATE TABLE {$wpdb->prefix}woocommerce_gzd_packaging ( + packaging_id BIGINT UNSIGNED NOT NULL auto_increment, + packaging_date_created datetime NOT NULL default '0000-00-00 00:00:00', + packaging_date_created_gmt datetime NOT NULL default '0000-00-00 00:00:00', + packaging_type varchar(200) NOT NULL DEFAULT '', + packaging_description TINYTEXT NOT NULL DEFAULT '', + packaging_weight DECIMAL(6,2) UNSIGNED NOT NULL DEFAULT 0, + packaging_order BIGINT UNSIGNED NOT NULL DEFAULT 0, + packaging_max_content_weight DECIMAL(6,2) UNSIGNED NOT NULL DEFAULT 0, + packaging_length DECIMAL(6,2) UNSIGNED NOT NULL DEFAULT 0, + packaging_width DECIMAL(6,2) UNSIGNED NOT NULL DEFAULT 0, + packaging_height DECIMAL(6,2) UNSIGNED NOT NULL DEFAULT 0, + PRIMARY KEY (packaging_id) +) $collate; +CREATE TABLE {$wpdb->prefix}woocommerce_gzd_packagingmeta ( + meta_id BIGINT UNSIGNED NOT NULL auto_increment, + gzd_packaging_id BIGINT UNSIGNED NOT NULL, + meta_key varchar(255) default NULL, + meta_value longtext NULL, + PRIMARY KEY (meta_id), + KEY gzd_packaging_id (gzd_packaging_id), + KEY meta_key (meta_key(32)) +) $collate; +CREATE TABLE {$wpdb->prefix}woocommerce_gzd_shipping_provider ( + shipping_provider_id BIGINT UNSIGNED NOT NULL auto_increment, + shipping_provider_activated TINYINT(1) NOT NULL default 1, + shipping_provider_title varchar(200) NOT NULL DEFAULT '', + shipping_provider_name varchar(191) NOT NULL DEFAULT '', + PRIMARY KEY (shipping_provider_id), + UNIQUE KEY shipping_provider_name (shipping_provider_name) +) $collate; +CREATE TABLE {$wpdb->prefix}woocommerce_gzd_shipping_providermeta ( + meta_id BIGINT UNSIGNED NOT NULL auto_increment, + gzd_shipping_provider_id BIGINT UNSIGNED NOT NULL, + meta_key varchar(255) default NULL, + meta_value longtext NULL, + PRIMARY KEY (meta_id), + KEY gzd_shipping_provider_id (gzd_shipping_provider_id), + KEY meta_key (meta_key(32)) +) $collate;"; + + return $tables; + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Interfaces/ShipmentLabel.php b/packages/woocommerce-germanized-shipments/src/Interfaces/ShipmentLabel.php new file mode 100644 index 000000000..7e5013dc0 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Interfaces/ShipmentLabel.php @@ -0,0 +1,97 @@ +get_shipping_provider_instance() ) { + if ( $provider->automatically_set_shipment_status_shipped( $shipment ) ) { + $shipment->set_status( 'shipped' ); + } + } + } + + public static function set_after_create_automation( $shipment_id, $shipment ) { + self::do_automation( $shipment, false ); + } + + /** + * @param Shipment $shipment + * @param boolean $is_hook + */ + protected static function do_automation( $shipment, $is_hook = true ) { + $disable = false; + + if ( ! $shipment->needs_label( false ) ) { + $disable = true; + } + + /** + * Filter that allows to disable automatically creating DHL labels for a certain shipment. + * + * @param boolean $disable True if you want to disable automation. + * @param Shipment $shipment The shipment object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/DHL + */ + $disable = apply_filters( 'woocommerce_gzd_shipments_disable_label_auto_generate', $disable, $shipment ); + + if ( $disable ) { + return; + } + + if ( $provider = $shipment->get_shipping_provider_instance() ) { + $hook_prefix = 'woocommerce_gzd_' . ( 'return' === $shipment->get_type() ? 'return_' : '' ) . 'shipment_status_'; + $auto_status = $provider->get_label_automation_shipment_status( $shipment ); + + if ( $provider->automatically_generate_label( $shipment ) && ! empty( $auto_status ) ) { + $status = str_replace( 'gzd-', '', $auto_status ); + + if ( $is_hook ) { + add_action( $hook_prefix . $status, array( __CLASS__, 'maybe_create_label' ), 5, 2 ); + } elseif ( $shipment->has_status( $status ) ) { + self::maybe_create_label( $shipment->get_id(), $shipment ); + } + } + } + } + + /** + * @param $shipment_id + * @param Shipment $shipment + */ + public static function set_automation( $shipment_id, $shipment ) { + self::do_automation( $shipment, true ); + } + + public static function create_label( $shipment_id, $shipment = false ) { + if ( ! $shipment ) { + $shipment = wc_gzd_get_shipment( $shipment_id ); + + if ( ! $shipment ) { + return; + } + } + + if ( ! $shipment->has_label() ) { + $result = $shipment->create_label(); + + if ( is_wp_error( $result ) ) { + Package::log( sprintf( 'Error while automatically creating label for %1$s: %2$s', $shipment->get_shipment_number(), wc_print_r( $result->get_error_messages(), true ) ) ); + } + } + } + + private static function is_admin_edit_order_request() { + return ( isset( $_POST['action'] ) && 'editpost' === $_POST['action'] && isset( $_POST['post_type'] ) && 'shop_order' === $_POST['post_type'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing + } + + public static function maybe_create_label( $shipment_id, $shipment = false ) { + // Make sure that MetaBox is saved before we process automation + if ( self::is_admin_edit_order_request() && ! did_action( 'woocommerce_process_shop_order_meta' ) ) { + add_action( 'woocommerce_process_shop_order_meta', array( __CLASS__, 'create_label' ), 70 ); + } else { + self::create_label( $shipment_id, $shipment ); + } + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Labels/DownloadHandler.php b/packages/woocommerce-germanized-shipments/src/Labels/DownloadHandler.php new file mode 100644 index 000000000..a99679a11 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Labels/DownloadHandler.php @@ -0,0 +1,133 @@ + isset( $_GET['force'] ) ? wc_clean( wp_unslash( $_GET['force'] ) ) : 'no', // phpcs:ignore WordPress.Security.NonceVerification.Recommended + 'path' => isset( $_GET['print'] ) ? wc_clean( wp_unslash( $_GET['print'] ) ) : 'no', // phpcs:ignore WordPress.Security.NonceVerification.Recommended + ); + + $args = self::parse_args( $args ); + + if ( current_user_can( 'edit_shop_orders' ) ) { + $handler = new BulkLabel(); + + if ( $path = $handler->get_file() ) { + $filename = $handler->get_filename(); + + self::download( $path, $filename, $args['force'] ); + } + } + } + } + } + + public static function download_label() { + if ( 'wc-gzd-download-shipment-label' === $_GET['action'] && wp_verify_nonce( wp_unslash( $_REQUEST['_wpnonce'] ), 'download-shipment-label' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + $shipment_id = absint( $_GET['shipment_id'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated + $has_permission = current_user_can( 'edit_shop_orders' ); + + $args = self::parse_args( + array( + 'force' => wc_string_to_bool( isset( $_GET['force'] ) ? wc_clean( wp_unslash( $_GET['force'] ) ) : false ), + ) + ); + + if ( $shipment = wc_gzd_get_shipment( $shipment_id ) ) { + if ( 'return' === $shipment->get_type() && current_user_can( 'view_order', $shipment->get_order_id() ) && $shipment->has_label() ) { + $has_permission = true; + } + + if ( $has_permission ) { + if ( $label = $shipment->get_label() ) { + $file = $label->get_file( $args['path'] ); + $filename = $label->get_filename( $args['path'] ); + + if ( file_exists( $file ) ) { + self::download( $file, $filename, $args['force'] ); + } + } + } + } + } + } + + public static function parse_args( $args = array() ) { + $args = wp_parse_args( + $args, + array( + 'force' => false, + 'path' => '', + ) + ); + + $args['force'] = wc_string_to_bool( $args['force'] ); + + return $args; + } + + public static function download( $path, $filename, $force = false ) { + if ( $force ) { + self::force( $path, $filename ); + } else { + self::embed( $path, $filename ); + } + } + + private static function force( $path, $filename ) { + WC_Download_Handler::download_file_force( $path, $filename ); + } + + private static function embed( $file_path, $filename ) { + if ( ob_get_level() ) { + $levels = ob_get_level(); + for ( $i = 0; $i < $levels; $i++ ) { + @ob_end_clean(); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged + } + } else { + @ob_end_clean(); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged + } + + wc_nocache_headers(); + + header( 'X-Robots-Tag: noindex, nofollow', true ); + header( 'Content-type: application/pdf' ); + header( 'Content-Description: File Transfer' ); + header( 'Content-Disposition: inline; filename="' . $filename . '";' ); + header( 'Content-Transfer-Encoding: binary' ); + + $file_size = @filesize( $file_path ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged + + if ( ! $file_size ) { + return; + } + + header( 'Content-Length: ' . $file_size ); + + @readfile( $file_path ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged,WordPress.WP.AlternativeFunctions.file_system_read_readfile + exit(); + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Labels/Factory.php b/packages/woocommerce-germanized-shipments/src/Labels/Factory.php new file mode 100644 index 000000000..49d52f456 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Labels/Factory.php @@ -0,0 +1,91 @@ +get_label_data( $label_id ); + + if ( $label_data ) { + $label_type = $label_data->type; + $shipping_provider_name = $label_data->shipping_provider; + } + } + + $shipping_provider_name = apply_filters( 'woocommerce_gzd_shipment_label_shipping_provider_name', $shipping_provider_name, $label_id, $label_type ); + + if ( ! $shipping_provider = wc_gzd_get_shipping_provider( $shipping_provider_name ) ) { + return false; + } + + /** + * Simple shipping provider do not support labels + */ + if ( ! is_a( $shipping_provider, '\Vendidero\Germanized\Shipments\Interfaces\ShippingProviderAuto' ) ) { + return false; + } + + $classname = $shipping_provider->get_label_classname( $label_type ); + + /** + * Filter that allows adjusting the default DHL label classname. + * + * @param string $classname The classname to be used. + * @param integer $label_id The label id. + * @param string $label_type The label type. + * + * @since 3.0.0 + * @package Vendidero/Germanized/DHL + */ + $classname = apply_filters( 'woocommerce_gzd_shipment_label_class', $classname, $label_id, $label_type, $shipping_provider ); + + if ( ! class_exists( $classname ) ) { + return false; + } + + try { + return new $classname( $label_id ); + } catch ( Exception $e ) { + wc_caught_exception( $e, __FUNCTION__, array( $label_id, $shipping_provider_name, $label_type ) ); + return false; + } + } + + public static function get_label_id( $label ) { + if ( is_numeric( $label ) ) { + return $label; + } elseif ( $label instanceof Label ) { + return $label->get_id(); + } elseif ( ! empty( $label->label_id ) ) { + return $label->label_id; + } else { + return false; + } + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Labels/Label.php b/packages/woocommerce-germanized-shipments/src/Labels/Label.php new file mode 100644 index 000000000..8be55bedc --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Labels/Label.php @@ -0,0 +1,858 @@ + null, + 'shipment_id' => 0, + 'product_id' => '', + 'parent_id' => 0, + 'number' => '', + 'shipping_provider' => '', + 'weight' => '', + 'net_weight' => '', + 'length' => '', + 'width' => '', + 'height' => '', + 'path' => '', + 'created_via' => '', + 'services' => array(), + ); + + public function __construct( $data = 0 ) { + parent::__construct( $data ); + + if ( $data instanceof ShipmentLabel ) { + $this->set_id( absint( $data->get_id() ) ); + } elseif ( is_numeric( $data ) ) { + $this->set_id( $data ); + } + + $this->data_store = WC_Data_Store::load( $this->data_store_name ); + + // If we have an ID, load the user from the DB. + if ( $this->get_id() ) { + try { + $this->data_store->read( $this ); + } catch ( Exception $e ) { + $this->set_id( 0 ); + $this->set_object_read( true ); + } + } else { + $this->set_object_read( true ); + } + } + + public function get_type() { + return 'simple'; + } + + /** + * Merge changes with data and clear. + * Overrides WC_Data::apply_changes. + * array_replace_recursive does not work well for license because it merges domains registered instead + * of replacing them. + * + * @since 3.2.0 + */ + public function apply_changes() { + if ( function_exists( 'array_replace' ) ) { + $this->data = array_replace( $this->data, $this->changes ); // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctions.array_replaceFound + } else { // PHP 5.2 compatibility. + foreach ( $this->changes as $key => $change ) { + $this->data[ $key ] = $change; + } + } + $this->changes = array(); + } + + /** + * Prefix for action and filter hooks on data. + * + * @since 3.0.0 + * @return string + */ + protected function get_general_hook_prefix() { + $prefix = 'simple' === $this->get_type() ? '' : $this->get_type() . '_'; + + return "woocommerce_gzd_shipment_{$prefix}label_"; + } + + /** + * Prefix for action and filter hooks on data. + * + * @since 3.0.0 + * @return string + */ + protected function get_hook_prefix() { + return $this->get_general_hook_prefix() . 'get_'; + } + + /** + * Return the date this license was created. + * + * @since 3.0.0 + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return WC_DateTime|null object if the date is set or null if there is no date. + */ + public function get_date_created( $context = 'view' ) { + return $this->get_prop( 'date_created', $context ); + } + + public function get_shipment_id( $context = 'view' ) { + return $this->get_prop( 'shipment_id', $context ); + } + + public function get_shipping_provider( $context = 'view' ) { + return $this->get_prop( 'shipping_provider', $context ); + } + + public function get_shipping_provider_instance() { + $provider = $this->get_shipping_provider(); + + if ( ! empty( $provider ) ) { + return wc_gzd_get_shipping_provider( $provider ); + } + + return false; + } + + public function get_parent_id( $context = 'view' ) { + return $this->get_prop( 'parent_id', $context ); + } + + public function get_created_via( $context = 'view' ) { + return $this->get_prop( 'created_via', $context ); + } + + public function get_product_id( $context = 'view' ) { + return $this->get_prop( 'product_id', $context ); + } + + public function get_number( $context = 'view' ) { + return $this->get_prop( 'number', $context ); + } + + public function has_number() { + $number = $this->get_number(); + + return empty( $number ) ? false : true; + } + + /** + * Returns the weight in kg + * + * @param string $context + * + * @return string + */ + public function get_weight( $context = 'view' ) { + return $this->get_prop( 'weight', $context ); + } + + public function get_net_weight( $context = 'view' ) { + $weight = $this->get_prop( 'net_weight', $context ); + + if ( 'view' === $context && '' === $weight ) { + $weight = $this->get_weight( $context ); + } + + return $weight; + } + + /** + * Returns the length in cm + * + * @param string $context + * + * @return string + */ + public function get_length( $context = 'view' ) { + return $this->get_prop( 'length', $context ); + } + + /** + * Returns the width in cm + * + * @param string $context + * + * @return string + */ + public function get_width( $context = 'view' ) { + return $this->get_prop( 'width', $context ); + } + + /** + * Returns the height in cm + * + * @param string $context + * + * @return string + */ + public function get_height( $context = 'view' ) { + return $this->get_prop( 'height', $context ); + } + + public function get_dimensions( $context = 'view' ) { + return array( + 'length' => $this->get_length( $context ), + 'width' => $this->get_width( $context ), + 'height' => $this->get_height( $context ), + ); + } + + public function has_dimensions() { + $width = $this->get_width(); + $length = $this->get_length(); + $height = $this->get_height(); + + return ( ! empty( $width ) && ! empty( $length ) && ! empty( $height ) ); + } + + public function get_path( $context = 'view', $file_path = '' ) { + return $this->get_prop( 'path', $context ); + } + + public function get_services( $context = 'view' ) { + return $this->get_prop( 'services', $context ); + } + + public function has_service( $service ) { + return ( in_array( $service, $this->get_services(), true ) ); + } + + public function get_shipment() { + if ( is_null( $this->shipment ) ) { + $this->shipment = ( $this->get_shipment_id() > 0 ? wc_gzd_get_shipment( $this->get_shipment_id() ) : false ); + } + + return $this->shipment; + } + + /* + |-------------------------------------------------------------------------- + | Setters + |-------------------------------------------------------------------------- + */ + + /** + * Set the date this license was last updated. + * + * @since 1.0.0 + * @param string|integer|null $date UTC timestamp, or ISO 8601 DateTime. If the DateTime string has no timezone or offset, WordPress site timezone will be assumed. Null if their is no date. + */ + public function set_date_created( $date = null ) { + $this->set_date_prop( 'date_created', $date ); + } + + public function set_number( $number ) { + $this->set_prop( 'number', $number ); + } + + public function set_product_id( $number ) { + $this->set_prop( 'product_id', $number ); + } + + public function set_shipping_provider( $slug ) { + $this->set_prop( 'shipping_provider', $slug ); + } + + public function set_parent_id( $id ) { + $this->set_prop( 'parent_id', absint( $id ) ); + } + + public function set_created_via( $created_via ) { + $this->set_prop( 'created_via', $created_via ); + } + + public function set_weight( $weight ) { + $this->set_prop( 'weight', '' !== $weight ? wc_format_decimal( $weight ) : '' ); + } + + public function set_net_weight( $weight ) { + $this->set_prop( 'net_weight', '' !== $weight ? wc_format_decimal( $weight ) : '' ); + } + + public function set_width( $width ) { + $this->set_prop( 'width', '' !== $width ? wc_format_decimal( $width ) : '' ); + } + + public function set_length( $length ) { + $this->set_prop( 'length', '' !== $length ? wc_format_decimal( $length ) : '' ); + } + + public function set_height( $height ) { + $this->set_prop( 'height', '' !== $height ? wc_format_decimal( $height ) : '' ); + } + + public function set_path( $path, $file_type = '' ) { + $this->set_prop( 'path', $path ); + } + + public function set_services( $services ) { + $this->set_prop( 'services', empty( $services ) ? array() : (array) $services ); + } + + /** + * Returns linked children labels. + * + * @return ShipmentLabel[] + */ + public function get_children() { + return wc_gzd_get_shipment_labels( array( 'parent_id' => $this->get_id() ) ); + } + + public function has_children() { + $children = $this->get_children(); + + return count( $children ) > 0 ? true : false; + } + + public function add_service( $service ) { + $services = (array) $this->get_services(); + $available_services = array(); + + if ( $provider = $this->get_shipping_provider_instance() ) { + if ( $shipment = $this->get_shipment() ) { + $available_services = $provider->get_available_label_services( $shipment ); + } + } + + if ( ! in_array( $service, $services, true ) && in_array( $service, $available_services, true ) ) { + $services[] = $service; + $this->set_services( $services ); + + return true; + } + + return false; + } + + public function remove_service( $service ) { + $services = (array) $this->get_services(); + + if ( in_array( $service, $services, true ) ) { + $services = array_diff( $services, array( $service ) ); + + $this->set_services( $services ); + return true; + } + + return false; + } + + public function supports_additional_file_type( $file_type ) { + return in_array( $file_type, $this->get_additional_file_types(), true ); + } + + public function get_additional_file_types() { + return array(); + } + + public function get_file( $file_type = '' ) { + if ( ! $path = $this->get_path( 'view', $file_type ) ) { + return false; + } + + return $this->get_file_by_path( $path ); + } + + protected function get_new_filename( $file_type = '' ) { + $file_parts = array( + $this->get_shipping_provider(), + ); + + if ( ! empty( $file_type ) ) { + $file_parts[] = $file_type; + } + + if ( 'simple' !== $this->get_type() ) { + $file_parts[] = $this->get_type(); + } + + $file_parts[] = $this->get_shipment_id(); + + $filename_default = implode( '-', $file_parts ); + $filename_default = $filename_default . '.pdf'; + $filename = apply_filters( "{$this->get_hook_prefix()}filename", $filename_default, $this, $file_type ); + + return sanitize_file_name( $filename ); + } + + public function get_filename( $file_type = '' ) { + if ( ! $path = $this->get_path( 'view', $file_type ) ) { + return $this->get_new_filename( $file_type ); + } + + return basename( $path ); + } + + protected function get_file_by_path( $file ) { + // If the file is relative, prepend upload dir. + if ( $file && 0 !== strpos( $file, '/' ) && ( ( $uploads = Package::get_upload_dir() ) && false === $uploads['error'] ) ) { + $file = $uploads['basedir'] . "/$file"; + + return $file; + } else { + return false; + } + } + + public function set_shipment_id( $shipment_id ) { + // Reset order object + $this->shipment = null; + + $this->set_prop( 'shipment_id', absint( $shipment_id ) ); + } + + /** + * @param Shipment $shipment + */ + public function set_shipment( &$shipment ) { + $this->shipment = $shipment; + + $this->set_prop( 'shipment_id', absint( $shipment->get_id() ) ); + } + + public function get_download_url( $args = array() ) { + $base_url = is_admin() ? admin_url() : trailingslashit( home_url() ); + $download_url = add_query_arg( + array( + 'action' => 'wc-gzd-download-shipment-label', + 'shipment_id' => $this->get_shipment_id(), + ), + wp_nonce_url( $base_url, 'download-shipment-label' ) + ); + + foreach ( $args as $arg => $val ) { + if ( is_bool( $val ) ) { + $args[ $arg ] = wc_bool_to_string( $val ); + } + } + + $download_url = add_query_arg( $args, $download_url ); + + /** + * Filter for shipping providers to adjust the label download URL. + * + * The dynamic portion of this hook, `$this->get_hook_prefix()` is used to construct a + * unique hook for a shipment type. `$provider` is related to the current shipping provider + * for the shipment (slug). + * + * Example hook name: `woocommerce_gzd_return_shipment_get_dhl_label_download_url` + * + * @param string $url The download URL. + * @param Label $label The current shipment instance. + * + * @since 3.0.6 + * @package Vendidero/Germanized/Shipments + */ + return esc_url_raw( apply_filters( "{$this->get_hook_prefix()}download_url", $download_url, $this ) ); + } + + /** + * @return \WP_Error|true + */ + public function fetch() { + $result = new \WP_Error( 'label-fetch-error', _x( 'This label misses the API implementation', 'shipments', 'woocommerce-germanized' ) ); + + return $result; + } + + /** + * @param $stream + * @param string $file_type + * + * @return false|string + */ + public function upload_label_file( $stream, $file_type = '' ) { + try { + Package::set_upload_dir_filter(); + $filename = $this->get_filename( $file_type ); + + $GLOBALS['gzd_shipments_unique_filename'] = $filename; + add_filter( 'wp_unique_filename', '_wc_gzd_shipments_keep_force_filename', 10, 1 ); + + $tmp = wp_upload_bits( $this->get_filename( $file_type ), null, $stream ); + + unset( $GLOBALS['gzd_shipments_unique_filename'] ); + remove_filter( 'wp_unique_filename', '_wc_gzd_shipments_keep_force_filename', 10 ); + + Package::unset_upload_dir_filter(); + + if ( isset( $tmp['file'] ) ) { + $path = $tmp['file']; + $path = Package::get_relative_upload_dir( $path ); + + $this->set_path( $path, $file_type ); + + return $path; + } else { + throw new Exception( _x( 'Error while uploading label.', 'shipments', 'woocommerce-germanized' ) ); + } + } catch ( Exception $e ) { + return false; + } + } + + /** + * @param $url + * @param string $file_type + * + * @return false|string + */ + public function download_label_file( $url, $file_type = '' ) { + $timeout_seconds = 5; + + try { + if ( ! function_exists( 'download_url' ) ) { + include_once ABSPATH . 'wp-admin/includes/file.php'; + } + + if ( ! function_exists( 'download_url' ) ) { + throw new \Exception( _x( 'Error while downloading the PDF file.', 'shipments', 'woocommerce-germanized' ) ); + } + + // Download file to temp dir. + $temp_file = download_url( $url, $timeout_seconds ); + + if ( is_wp_error( $temp_file ) ) { + throw new \Exception( _x( 'Error while downloading the PDF file.', 'shipments', 'woocommerce-germanized' ) ); + } + + $file = array( + 'name' => $this->get_filename( $file_type ), + 'type' => 'application/pdf', + 'tmp_name' => $temp_file, + 'error' => 0, + 'size' => filesize( $temp_file ), + ); + + $overrides = array( + 'test_type' => false, + 'test_form' => false, + 'test_size' => true, + ); + + // Move the temporary file into the uploads directory. + Package::set_upload_dir_filter(); + $results = wp_handle_sideload( $file, $overrides ); + Package::unset_upload_dir_filter(); + + if ( empty( $results['error'] ) ) { + $path = Package::get_relative_upload_dir( $results['file'] ); + + $this->set_path( $path, $file_type ); + + return $path; + } else { + throw new \Exception( _x( 'Error while downloading the PDF file.', 'shipments', 'woocommerce-germanized' ) ); + } + } catch ( \Exception $e ) { + return false; + } + } + + public function is_trackable() { + return true; + } + + public function supports_third_party_email_notification() { + $supports_email_notification = false; + + if ( ( $shipment = $this->get_shipment() ) && ( $order = $shipment->get_order() ) ) { + $supports_email_notification = wc_gzd_order_supports_parcel_delivery_reminder( $order ); + } + + return apply_filters( "{$this->get_general_hook_prefix()}supports_third_party_email_notification", $supports_email_notification, $this ); + } + + /** + * Gets a prop for a getter method. + * + * @since 3.0.0 + * @param string $prop Name of prop to get. + * @param string $address billing or shipping. + * @param string $context What the value is for. Valid values are view and edit. + * @return mixed + */ + protected function get_address_prop( $prop, $address = 'sender_address', $context = 'view' ) { + $value = null; + + if ( isset( $this->changes[ $address ][ $prop ] ) || isset( $this->data[ $address ][ $prop ] ) ) { + $value = isset( $this->changes[ $address ][ $prop ] ) ? $this->changes[ $address ][ $prop ] : $this->data[ $address ][ $prop ]; + + if ( 'view' === $context ) { + /** + * Filter to adjust a specific address property for a DHL label. + * + * The dynamic portion of the hook name, `$this->get_hook_prefix()` constructs an individual + * hook name which uses `woocommerce_gzd_dhl_label_get_` as a prefix. Additionally + * `$address` contains the current address type e.g. sender_address and `$prop` contains the actual + * property e.g. street. + * + * Example hook name: `woocommerce_gzd_dhl_return_label_get_sender_address_street` + * + * @param string $value The address property value. + * @param \Vendidero\Germanized\DHL\Label\Label $label The label object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/DHL + */ + $value = apply_filters( "{$this->get_hook_prefix()}{$address}_{$prop}", $value, $this ); + } + } + + return $value; + } + + protected function round_customs_item_weight( $value, $precision = 0 ) { + return \Automattic\WooCommerce\Utilities\NumberUtil::round( $value, $precision, 2 ); + } + + protected function get_per_item_weights( $total_weight, $item_weights, $shipment_items ) { + $item_total_weight = array_sum( $item_weights ); + $item_count = count( $item_weights ); + + /** + * Discrepancies detected between item weights an total shipment weight. + * Try to distribute the mismatch between items. + */ + if ( $item_total_weight != $total_weight ) { // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison + $diff = $total_weight - $item_total_weight; + $diff_abs = abs( $diff ); + + if ( $diff_abs > 0 ) { + $per_item_diff = $diff / $item_count; + // Round down to int + $per_item_diff_rounded = $this->round_customs_item_weight( $per_item_diff ); + $diff_applied = 0; + + if ( abs( $per_item_diff_rounded ) > 0 ) { + foreach ( $item_weights as $key => $weight ) { + $shipment_item = $shipment_items[ $key ]; + $item_min_weight = 1 * $shipment_item->get_quantity(); + + $item_weight_before = $item_weights[ $key ]; + $new_item_weight = $item_weights[ $key ] += $per_item_diff_rounded; + $item_diff_applied = $per_item_diff_rounded; + + /** + * In case the diff is negative make sure we are not + * subtracting more than available as min weight per item. + */ + if ( $new_item_weight <= $item_min_weight ) { + $new_item_weight = $item_min_weight; + $item_diff_applied = $item_min_weight - $item_weight_before; + } + + $item_weights[ $key ] = $new_item_weight; + $diff_applied += $item_diff_applied; + } + } + + // Check rounding diff and apply the diff to one item + $diff_left = $diff - $diff_applied; + + if ( abs( $diff_left ) > 0 ) { + foreach ( $item_weights as $key => $weight ) { + $shipment_item = $shipment_items[ $key ]; + $item_min_weight = 1 * $shipment_item->get_quantity(); + + if ( $diff_left > 0 ) { + /** + * Add the diff left to the first item and stop. + */ + $item_weights[ $key ] += $diff_left; + break; + } else { + /** + * Remove the diff left from the first item with a weight greater than 0.01 to prevent 0 weights. + */ + if ( $weight > $item_min_weight ) { + $item_weights[ $key ] += $diff_left; + break; + } + } + } + } + } + } + + return $item_weights; + } + + public function get_customs_data( $max_desc_length = 255 ) { + if ( ! $shipment = $this->get_shipment() ) { + return false; + } + + $customs_items = array(); + $item_description = ''; + $total_weight = $this->round_customs_item_weight( wc_add_number_precision( $this->get_net_weight() ) ); + $total_gross_weight = $this->round_customs_item_weight( wc_add_number_precision( $this->get_weight() ) ); + $item_weights = array(); + $shipment_items = $shipment->get_items(); + $order = $shipment->get_order(); + + foreach ( $shipment_items as $key => $item ) { + $per_item_weight = wc_format_decimal( floatval( wc_get_weight( $item->get_weight(), 'kg', $shipment->get_weight_unit() ) ), 2 ); + $per_item_weight = wc_add_number_precision( $per_item_weight ); + $per_item_weight = $per_item_weight * $item->get_quantity(); + $per_item_min_weight = 1 * $item->get_quantity(); + + /** + * Set min weight to 0.01 to prevent missing weight error messages + * for really small product weights. + */ + if ( $per_item_weight < $per_item_min_weight ) { + $per_item_weight = $per_item_min_weight; + } + + $item_weights[ $key ] = $per_item_weight; + } + + $item_weights = $this->get_per_item_weights( $total_weight, $item_weights, $shipment_items ); + $item_gross_weights = $this->get_per_item_weights( $total_gross_weight, $item_weights, $shipment_items ); + $total_weight = 0; + $total_gross_weight = 0; + $total_value = 0; + $use_subtotal = false; + + if ( $order && apply_filters( 'woocommerce_gzd_shipments_order_has_voucher', false, $order ) ) { + $use_subtotal = true; + } + + $use_subtotal = apply_filters( 'woocommerce_gzd_shipments_customs_use_subtotal', $use_subtotal, $this ); + + foreach ( $shipment->get_items() as $key => $item ) { + $item_description .= ! empty( $item_description ) ? ', ' : ''; + $item_description .= $item->get_name(); + + // Use total before discounts for customs + $product_total = floatval( (float) ( $use_subtotal ? $item->get_subtotal() : $item->get_total() ) / $item->get_quantity() ); + $dhl_product = false; + $product = $item->get_product(); + + if ( $product ) { + $shipment_product = wc_gzd_shipments_get_product( $product ); + } + + if ( $product_total < 0.01 ) { + // Use the order item data as fallback + if ( ( $order_item = $item->get_order_item() ) && $order ) { + $order_item_total = $use_subtotal ? $order->get_line_subtotal( $order_item, true, false ) : $order->get_line_total( $order_item, true, false ); + $product_total = floatval( (float) $order_item_total / $item->get_quantity() ); + } + } + + $category = $shipment_product ? $shipment_product->get_main_category() : $item->get_name(); + + if ( empty( $category ) ) { + $category = $item->get_name(); + } + + $product_value = $product_total < 0.01 ? wc_format_decimal( apply_filters( "{$this->get_general_hook_prefix()}customs_item_min_price", 0.01, $item, $this, $shipment ), 2 ) : wc_format_decimal( $product_total, 2 ); + + $customs_items[ $key ] = apply_filters( + "{$this->get_general_hook_prefix()}customs_item", + array( + 'description' => apply_filters( "{$this->get_general_hook_prefix()}item_description", wc_clean( mb_substr( $item->get_name(), 0, $max_desc_length ) ), $item, $this, $shipment ), + 'category' => apply_filters( "{$this->get_general_hook_prefix()}item_category", $category, $item, $this, $shipment ), + 'origin_code' => ( $shipment_product && $shipment_product->get_manufacture_country() ) ? $shipment_product->get_manufacture_country() : Package::get_base_country(), + 'tariff_number' => $shipment_product ? $shipment_product->get_hs_code() : '', + 'quantity' => intval( $item->get_quantity() ), + 'weight_in_kg' => wc_remove_number_precision( $item_weights[ $key ] ), + 'single_weight_in_kg' => $this->round_customs_item_weight( wc_remove_number_precision( $item_weights[ $key ] / $item->get_quantity() ), 2 ), + 'weight_in_kg_raw' => $item_weights[ $key ], + 'gross_weight_in_kg' => wc_remove_number_precision( $item_gross_weights[ $key ] ), + 'single_gross_weight_in_kg' => $this->round_customs_item_weight( wc_remove_number_precision( $item_gross_weights[ $key ] / $item->get_quantity() ), 2 ), + 'gross_weight_in_kg_raw' => $item_gross_weights[ $key ], + 'single_value' => $product_value, + 'value' => wc_format_decimal( $product_value * $item->get_quantity(), 2 ), + ), + $item, + $shipment, + $this + ); + + $total_weight += (float) $customs_items[ $key ]['weight_in_kg']; + $total_gross_weight += (float) $customs_items[ $key ]['gross_weight_in_kg']; + $total_value += (float) $customs_items[ $key ]['value']; + } + + $item_description = mb_substr( $item_description, 0, $max_desc_length ); + + $customs_data = apply_filters( + "{$this->get_general_hook_prefix()}customs_data", + array( + 'shipment_id' => $shipment->get_id(), + 'additional_fee' => wc_format_decimal( $shipment->get_additional_total(), 2 ), + 'export_type_description' => $item_description, + 'place_of_commital' => $shipment->get_sender_city(), + // e.g. EORI number + 'sender_customs_ref_number' => $shipment->get_sender_customs_reference_number(), + 'receiver_customs_ref_number' => $shipment->get_customs_reference_number(), + 'items' => $customs_items, + 'item_total_weight_in_kg' => $total_weight, + 'item_total_gross_weight_in_kg' => $total_gross_weight, + 'item_total_value' => $total_value, + 'currency' => $order ? $order->get_currency() : get_woocommerce_currency(), + 'invoice_number' => '', + ), + $this, + $shipment + ); + + return $customs_data; + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Labels/Query.php b/packages/woocommerce-germanized-shipments/src/Labels/Query.php new file mode 100644 index 000000000..8a2d8c8eb --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Labels/Query.php @@ -0,0 +1,490 @@ + 10, + 'shipment_id' => '', + 'product_id' => '', + 'shipping_provider' => '', + 'parent_id' => '', + 'type' => wc_gzd_get_shipment_label_types(), + 'number' => '', + 'order' => 'DESC', + 'orderby' => 'date_created', + 'return' => 'objects', + 'page' => 1, + 'offset' => '', + 'paginate' => false, + 'search' => '', + 'search_columns' => array(), + ); + } + + /** + * Get labels matching the current query vars. + * + * @return Label[] objects + * + * @throws \Exception When WC_Data_Store validation fails. + */ + public function get_labels() { + /** + * Filter to adjust query paramaters for a DHL label query. + * + * @param array $query_vars The query arguments. + * + * @since 3.0.0 + * @package Vendidero/Germanized/DHL + */ + $args = apply_filters( 'woocommerce_gzd_shipment_label_query_args', $this->get_query_vars() ); + $args = WC_Data_Store::load( 'shipment-label' )->get_query_args( $args ); + + $this->query( $args ); + + /** + * Filter to adjust query result data for a DHL label query. + * + * @param Label[] $results The results. + * @param array $args The query arguments. + * + * @since 3.0.0 + * @package Vendidero/Germanized/DHL + */ + return apply_filters( 'woocommerce_gzd_shipment_label_query', $this->results, $args ); + } + + public function get_total() { + return $this->total_labels; + } + + /** + * Query shipments. + * + * @param array $query_args + */ + protected function query( $query_args ) { + global $wpdb; + + $this->args = $query_args; + $this->parse_query(); + $this->prepare_query(); + + $qv =& $this->args; + + $this->results = null; + + if ( null === $this->results ) { + $this->request = "SELECT $this->query_fields $this->query_from $this->query_where $this->query_orderby $this->query_limit"; + + if ( is_array( $qv['fields'] ) || 'objects' === $qv['fields'] ) { + $this->results = $wpdb->get_results( $this->request ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + } else { + $this->results = $wpdb->get_col( $this->request ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + } + + if ( isset( $qv['count_total'] ) && $qv['count_total'] ) { + $found_labels_query = 'SELECT FOUND_ROWS()'; + $this->total_labels = (int) $wpdb->get_var( $found_labels_query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + } + } + + if ( ! $this->results ) { + return; + } + + if ( 'objects' === $qv['fields'] ) { + foreach ( $this->results as $key => $label ) { + $this->results[ $key ] = wc_gzd_get_shipment_label( $label ); + } + } + } + + /** + * Parse the query before preparing it. + */ + protected function parse_query() { + + if ( isset( $this->args['shipment_id'] ) ) { + $this->args['shipment_id'] = absint( $this->args['shipment_id'] ); + } + + if ( isset( $this->args['shipping_provider'] ) ) { + $this->args['shipping_provider'] = sanitize_key( $this->args['shipping_provider'] ); + } + + if ( isset( $this->args['product_id'] ) ) { + $this->args['product_id'] = wc_clean( $this->args['product_id'] ); + } + + if ( isset( $this->args['parent_id'] ) && ! empty( $this->args['parent_id'] ) ) { + $this->args['parent_id'] = absint( $this->args['parent_id'] ); + } + + if ( isset( $this->args['number'] ) ) { + $this->args['number'] = sanitize_key( $this->args['number'] ); + } + + if ( isset( $this->args['type'] ) ) { + $this->args['type'] = (array) $this->args['type']; + $this->args['type'] = array_map( 'wc_clean', $this->args['type'] ); + } + + if ( isset( $this->args['search'] ) ) { + $this->args['search'] = wc_clean( $this->args['search'] ); + + if ( ! isset( $this->args['search_columns'] ) ) { + $this->args['search_columns'] = array(); + } + } + } + + /** + * Prepare the query for DB usage. + */ + protected function prepare_query() { + global $wpdb; + + if ( is_array( $this->args['fields'] ) ) { + $this->args['fields'] = array_unique( $this->args['fields'] ); + + $this->query_fields = array(); + + foreach ( $this->args['fields'] as $field ) { + $field = 'ID' === $field ? 'label_id' : sanitize_key( $field ); + $this->query_fields[] = "$wpdb->gzd_shipment_labels.$field"; + } + + $this->query_fields = implode( ',', $this->query_fields ); + + } elseif ( 'objects' === $this->args['fields'] ) { + $this->query_fields = "$wpdb->gzd_shipment_labels.*"; + } else { + $this->query_fields = "$wpdb->gzd_shipment_labels.label_id"; + } + + if ( isset( $this->args['count_total'] ) && $this->args['count_total'] ) { + $this->query_fields = 'SQL_CALC_FOUND_ROWS ' . $this->query_fields; + } + + $this->query_from = "FROM $wpdb->gzd_shipment_labels"; + $this->query_where = 'WHERE 1=1'; + + // order id + if ( isset( $this->args['shipment_id'] ) ) { + $this->query_where .= $wpdb->prepare( ' AND label_shipment_id = %d', $this->args['shipment_id'] ); + } + + // parent id + if ( isset( $this->args['parent_id'] ) ) { + $this->query_where .= $wpdb->prepare( ' AND label_parent_id = %d', $this->args['parent_id'] ); + } + + // Number + if ( isset( $this->args['number'] ) ) { + $this->query_where .= $wpdb->prepare( " AND label_number IN ('%s')", $this->args['number'] ); // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.QuotedSimplePlaceholder + } + + // Shipping provider + if ( isset( $this->args['shipping_provider'] ) ) { + $this->query_where .= $wpdb->prepare( " AND label_shipping_provider IN ('%s')", $this->args['shipping_provider'] ); // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.QuotedSimplePlaceholder + } + + // Shipping provider + if ( isset( $this->args['product_id'] ) ) { + $this->query_where .= $wpdb->prepare( " AND label_product_id IN ('%s')", $this->args['product_id'] ); // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.QuotedSimplePlaceholder + } + + // type + if ( isset( $this->args['type'] ) ) { + $types = $this->args['type']; + $p_types = array(); + + foreach ( $types as $type ) { + $p_types[] = $wpdb->prepare( 'label_type = %s', $type ); + } + + $where_type = implode( ' OR ', $p_types ); + + if ( ! empty( $where_type ) ) { + $this->query_where .= " AND ($where_type)"; + } + } + + // Search + $search = ''; + + if ( isset( $this->args['search'] ) ) { + $search = trim( $this->args['search'] ); + } + + if ( $search ) { + + $leading_wild = ( ltrim( $search, '*' ) !== $search ); + $trailing_wild = ( rtrim( $search, '*' ) !== $search ); + + if ( $leading_wild && $trailing_wild ) { + $wild = 'both'; + } elseif ( $leading_wild ) { + $wild = 'leading'; + } elseif ( $trailing_wild ) { + $wild = 'trailing'; + } else { + $wild = false; + } + if ( $wild ) { + $search = trim( $search, '*' ); + } + + $search_columns = array(); + + if ( $this->args['search_columns'] ) { + $search_columns = array_intersect( $this->args['search_columns'], array( 'label_id', 'label_path', 'label_number', 'label_shipment_id', 'label_product_id' ) ); + } + + if ( ! $search_columns ) { + if ( is_numeric( $search ) ) { + $search_columns = array( 'label_id', 'label_shipment_id' ); + } else { + $search_columns = array( 'label_id', 'label_path', 'label_number', 'label_shipment_id', 'label_product_id' ); + } + } + + /** + * Filters the columns to search in a DHL LabelQuery search. + * + * The default columns depend on the search term, and include 'label_id', + * 'label_shipment_id', 'label_path' and 'label_number'. + * + * @since 3.0.0 + * + * @param string[] $search_columns Array of column names to be searched. + * @param string $search Text being searched. + * @param LabelQuery $this The current LabelQuery instance. + * + * @package Vendidero/Germanized/DHL + */ + $search_columns = apply_filters( 'woocommerce_gzd_shipment_label_search_columns', $search_columns, $search, $this ); + + $this->query_where .= $this->get_search_sql( $search, $search_columns, $wild ); + } + + // Parse and sanitize 'include', for use by 'orderby' as well as 'include' below. + if ( ! empty( $this->args['include'] ) ) { + $include = wp_parse_id_list( $this->args['include'] ); + } else { + $include = false; + } + + // Meta query. + $this->meta_query = new WP_Meta_Query(); + $this->meta_query->parse_query_vars( $this->args ); + + if ( ! empty( $this->meta_query->queries ) ) { + $clauses = $this->meta_query->get_sql( 'gzd_shipment_label', $wpdb->gzd_shipment_labels, 'label_id', $this ); + $this->query_from .= $clauses['join']; + $this->query_where .= $clauses['where']; + + if ( $this->meta_query->has_or_relation() ) { + $this->query_fields = 'DISTINCT ' . $this->query_fields; + } + } + + // sorting + $this->args['order'] = isset( $this->args['order'] ) ? strtoupper( $this->args['order'] ) : ''; + $order = $this->parse_order( $this->args['order'] ); + + if ( empty( $this->args['orderby'] ) ) { + // Default order is by 'user_login'. + $ordersby = array( 'date_created' => $order ); + } elseif ( is_array( $this->args['orderby'] ) ) { + $ordersby = $this->args['orderby']; + } else { + // 'orderby' values may be a comma- or space-separated list. + $ordersby = preg_split( '/[,\s]+/', $this->args['orderby'] ); + } + + $orderby_array = array(); + + foreach ( $ordersby as $_key => $_value ) { + if ( ! $_value ) { + continue; + } + + if ( is_int( $_key ) ) { + // Integer key means this is a flat array of 'orderby' fields. + $_orderby = $_value; + $_order = $order; + } else { + // Non-integer key means this the key is the field and the value is ASC/DESC. + $_orderby = $_key; + $_order = $_value; + } + + $parsed = $this->parse_orderby( $_orderby ); + + if ( ! $parsed ) { + continue; + } + + $orderby_array[] = $parsed . ' ' . $this->parse_order( $_order ); + } + + // If no valid clauses were found, order by user_login. + if ( empty( $orderby_array ) ) { + $orderby_array[] = "label_id $order"; + } + + $this->query_orderby = 'ORDER BY ' . implode( ', ', $orderby_array ); + + // limit + if ( isset( $this->args['posts_per_page'] ) && $this->args['posts_per_page'] > 0 ) { + if ( isset( $this->args['offset'] ) ) { + $this->query_limit = $wpdb->prepare( 'LIMIT %d, %d', $this->args['offset'], $this->args['posts_per_page'] ); + } else { + $this->query_limit = $wpdb->prepare( 'LIMIT %d, %d', $this->args['posts_per_page'] * ( $this->args['page'] - 1 ), $this->args['posts_per_page'] ); + } + } + + if ( ! empty( $include ) ) { + // Sanitized earlier. + $ids = implode( ',', $include ); + $this->query_where .= " AND $wpdb->gzd_shipment_labels.label_id IN ($ids)"; + } elseif ( ! empty( $this->args['exclude'] ) ) { + $ids = implode( ',', wp_parse_id_list( $this->args['exclude'] ) ); + $this->query_where .= " AND $wpdb->gzd_shipment_labels.label_id NOT IN ($ids)"; + } + + // Date queries are allowed for the user_registered field. + if ( ! empty( $this->args['date_query'] ) && is_array( $this->args['date_query'] ) ) { + $date_query = new WP_Date_Query( $this->args['date_query'], 'label_date_created' ); + $this->query_where .= $date_query->get_sql(); + } + } + + /** + * Used internally to generate an SQL string for searching across multiple columns + * + * @since 3.0.6 + * + * @global \wpdb $wpdb WordPress database abstraction object. + * + * @param string $string + * @param array $cols + * @param bool $wild Whether to allow wildcard searches. Default is false for Network Admin, true for single site. + * Single site allows leading and trailing wildcards, Network Admin only trailing. + * @return string + */ + protected function get_search_sql( $string, $cols, $wild = false ) { + global $wpdb; + + $searches = array(); + $leading_wild = ( 'leading' === $wild || 'both' === $wild ) ? '%' : ''; + $trailing_wild = ( 'trailing' === $wild || 'both' === $wild ) ? '%' : ''; + $like = $leading_wild . $wpdb->esc_like( $string ) . $trailing_wild; + + foreach ( $cols as $col ) { + if ( 'ID' === $col ) { + $searches[] = $wpdb->prepare( "$col = %s", $string ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared + } else { + $searches[] = $wpdb->prepare( "$col LIKE %s", $like ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared + } + } + + return ' AND (' . implode( ' OR ', $searches ) . ')'; + } + + /** + * Parse orderby statement. + * + * @param string $orderby + * @return string + */ + protected function parse_orderby( $orderby ) { + global $wpdb; + + $meta_query_clauses = $this->meta_query->get_clauses(); + + $_orderby = ''; + + if ( in_array( $orderby, array( 'number', 'shipment_id', 'date_created' ), true ) ) { + $_orderby = 'label_' . $orderby; + } elseif ( 'ID' === $orderby || 'id' === $orderby ) { + $_orderby = 'label_id'; + } elseif ( 'meta_value' === $orderby || $this->get( 'meta_key' ) === $orderby ) { + $_orderby = "$wpdb->gzd_shipment_labelmeta.meta_value"; + } elseif ( 'meta_value_num' === $orderby ) { + $_orderby = "$wpdb->gzd_shipment_labelmeta.meta_value+0"; + } elseif ( 'include' === $orderby && ! empty( $this->args['include'] ) ) { + $include = wp_parse_id_list( $this->args['include'] ); + $include_sql = implode( ',', $include ); + $_orderby = "FIELD( $wpdb->gzd_shipment_labels.label_id, $include_sql )"; + } elseif ( isset( $meta_query_clauses[ $orderby ] ) ) { + $meta_clause = $meta_query_clauses[ $orderby ]; + $_orderby = sprintf( 'CAST(%s.meta_value AS %s)', esc_sql( $meta_clause['alias'] ), esc_sql( $meta_clause['cast'] ) ); + } + + return $_orderby; + } + + /** + * Parse order statement. + * + * @param string $order + * @return string + */ + protected function parse_order( $order ) { + if ( ! is_string( $order ) || empty( $order ) ) { + return 'DESC'; + } + + if ( 'ASC' === strtoupper( $order ) ) { + return 'ASC'; + } else { + return 'DESC'; + } + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Labels/ReturnLabel.php b/packages/woocommerce-germanized-shipments/src/Labels/ReturnLabel.php new file mode 100644 index 000000000..53b3494a7 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Labels/ReturnLabel.php @@ -0,0 +1,119 @@ + array(), + ); + + public function get_type() { + return 'return'; + } + + public function get_sender_address( $context = 'view' ) { + return $this->get_prop( 'sender_address', $context ); + } + + /** + * Gets a prop for a getter method. + * + * @since 3.0.0 + * @param string $prop Name of prop to get. + * @param string $address billing or shipping. + * @param string $context What the value is for. Valid values are view and edit. + * @return mixed + */ + protected function get_sender_address_prop( $prop, $context = 'view' ) { + $value = $this->get_address_prop( $prop, 'sender_address', $context ); + + return $value; + } + + public function get_sender_address_2( $context = 'view' ) { + return $this->get_sender_address_prop( 'address_2', $context ); + } + + public function get_sender_address_addition() { + $addition = $this->get_sender_address_2(); + $street_addition = $this->get_sender_street_addition(); + + if ( ! empty( $street_addition ) ) { + $addition = $street_addition . ( ! empty( $addition ) ? ' ' . $addition : '' ); + } + + return trim( $addition ); + } + + public function get_sender_street( $context = 'view' ) { + return $this->get_sender_address_prop( 'street', $context ); + } + + public function get_sender_street_number( $context = 'view' ) { + return $this->get_sender_address_prop( 'street_number', $context ); + } + + public function get_sender_street_addition( $context = 'view' ) { + return $this->get_sender_address_prop( 'street_addition', $context ); + } + + public function get_sender_company( $context = 'view' ) { + return $this->get_sender_address_prop( 'company', $context ); + } + + public function get_sender_name( $context = 'view' ) { + return $this->get_sender_address_prop( 'name', $context ); + } + + public function get_sender_formatted_full_name() { + return sprintf( _x( '%1$s', 'shipments full name', 'woocommerce-germanized' ), $this->get_sender_name() ); // phpcs:ignore WordPress.WP.I18n.NoEmptyStrings + } + + public function get_sender_postcode( $context = 'view' ) { + return $this->get_sender_address_prop( 'postcode', $context ); + } + + public function get_sender_city( $context = 'view' ) { + return $this->get_sender_address_prop( 'city', $context ); + } + + public function get_sender_state( $context = 'view' ) { + return $this->get_sender_address_prop( 'state', $context ); + } + + public function get_sender_country( $context = 'view' ) { + return $this->get_sender_address_prop( 'country', $context ); + } + + public function get_sender_phone( $context = 'view' ) { + return $this->get_sender_address_prop( 'phone', $context ); + } + + public function get_sender_email( $context = 'view' ) { + return $this->get_sender_address_prop( 'email', $context ); + } + + public function set_sender_address( $value ) { + $this->set_prop( 'sender_address', empty( $value ) ? array() : (array) $value ); + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Order.php b/packages/woocommerce-germanized-shipments/src/Order.php new file mode 100644 index 000000000..c07857c16 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Order.php @@ -0,0 +1,1007 @@ +order = $order; + } + + /** + * Returns the Woo WC_Order original object + * + * @return object|WC_Order + */ + public function get_order() { + return $this->order; + } + + /** + * @return WC_DateTime|null + */ + public function get_date_shipped() { + $date_shipped = $this->get_order()->get_meta( '_date_shipped', true ); + + if ( $date_shipped ) { + try { + $date_shipped = new WC_DateTime( "@{$date_shipped}" ); + + // Set local timezone or offset. + if ( get_option( 'timezone_string' ) ) { + $date_shipped->setTimezone( new DateTimeZone( wc_timezone_string() ) ); + } else { + $date_shipped->set_utc_offset( wc_timezone_offset() ); + } + } catch ( Exception $e ) { + $date_shipped = null; + } + } else { + $date_shipped = null; + } + + return $date_shipped; + } + + public function is_shipped() { + $shipping_status = $this->get_shipping_status(); + + return apply_filters( 'woocommerce_gzd_shipment_order_shipping_status', ( in_array( $shipping_status, array( 'shipped', 'delivered' ), true ) || ( 'partially-delivered' === $shipping_status && ! $this->needs_shipping( array( 'sent_only' => true ) ) ) ), $this ); + } + + public function get_shipping_status() { + $status = 'not-shipped'; + $shipments = $this->get_simple_shipments(); + $all_shipments_delivered = false; + $all_shipments_shipped = false; + + if ( ! empty( $shipments ) ) { + $all_shipments_delivered = true; + $all_shipments_shipped = true; + + foreach ( $shipments as $shipment ) { + if ( ! $shipment->has_status( 'delivered' ) ) { + $all_shipments_delivered = false; + } else { + $status = 'partially-delivered'; + } + + if ( ! $shipment->is_shipped() ) { + $all_shipments_shipped = false; + } elseif ( 'partially-delivered' !== $status ) { + $status = 'partially-shipped'; + } + } + } + + $needs_shipping = $this->needs_shipping( array( 'sent_only' => true ) ); + + if ( $all_shipments_delivered && ! $needs_shipping ) { + $status = 'delivered'; + } elseif ( 'partially-delivered' !== $status && ( $all_shipments_shipped && ! $needs_shipping ) ) { + $status = 'shipped'; + } elseif ( ! in_array( $status, array( 'partially-shipped', 'partially-delivered' ), true ) && ! $needs_shipping ) { + $status = 'no-shipping-needed'; + } + + return apply_filters( 'woocommerce_gzd_shipment_order_shipping_status', $status, $this ); + } + + public function has_shipped_shipments() { + $shipments = $this->get_simple_shipments(); + + foreach ( $shipments as $shipment ) { + if ( $shipment->is_shipped() ) { + return true; + } + } + + return false; + } + + public function get_return_status() { + $status = 'open'; + $shipments = $this->get_return_shipments(); + + if ( ! empty( $shipments ) ) { + foreach ( $shipments as $shipment ) { + if ( $shipment->has_status( 'delivered' ) ) { + $status = 'partially-returned'; + break; + } + } + } + + if ( ! $this->needs_return( array( 'delivered_only' => true ) ) && $this->has_shipped_shipments() ) { + $status = 'returned'; + } + + return $status; + } + + public function get_default_return_shipping_provider() { + $default_provider_instance = wc_gzd_get_order_shipping_provider( $this->get_order() ); + $default_provider = $default_provider_instance ? $default_provider_instance->get_name() : ''; + $shipments = $this->get_simple_shipments(); + + foreach ( $shipments as $shipment ) { + if ( $shipment->is_shipped() ) { + $default_provider = $shipment->get_shipping_provider(); + } + } + + return apply_filters( 'woocommerce_gzd_shipment_order_return_default_shipping_provider', $default_provider, $this ); + } + + public function validate_shipments( $args = array() ) { + $args = wp_parse_args( + $args, + array( + 'save' => true, + ) + ); + + foreach ( $this->get_simple_shipments() as $shipment ) { + if ( $shipment->is_editable() ) { + + // Make sure we are working based on the current instance. + $shipment->set_order_shipment( $this ); + $shipment->sync(); + + $this->validate_shipment_item_quantities( $shipment->get_id() ); + } + } + + if ( $args['save'] ) { + $this->save(); + } + } + + /** + * @param Shipment $shipment + */ + public function calculate_shipment_additional_total( $shipment ) { + $fees_total = 0; + + foreach ( $this->get_order()->get_fees() as $item ) { + $fees_total += ( (float) $item->get_total() + (float) $item->get_total_tax() ); + } + + $additional_total = $fees_total + $this->get_order()->get_shipping_total() + $this->get_order()->get_shipping_tax(); + + foreach ( $this->get_simple_shipments() as $simple_shipment ) { + if ( $shipment->get_id() === $simple_shipment->get_id() ) { + continue; + } + + $additional_total -= (float) $simple_shipment->get_additional_total(); + } + + $additional_total = wc_format_decimal( $additional_total, '' ); + + if ( $additional_total < 0 ) { + $additional_total = 0; + } + + return $additional_total; + } + + public function validate_shipment_item_quantities( $shipment_id = false ) { + $shipment = $shipment_id ? $this->get_shipment( $shipment_id ) : false; + $shipments = ( $shipment_id && $shipment ) ? array( $shipment ) : $this->get_simple_shipments(); + $order_items = $this->get_shippable_items(); + + foreach ( $shipments as $shipment ) { + + if ( ! is_a( $shipment, 'Vendidero\Germanized\Shipments\Shipment' ) ) { + continue; + } + + // Do only check draft shipments + if ( $shipment->is_editable() ) { + foreach ( $shipment->get_items() as $item ) { + + // Order item does not exist + if ( ! isset( $order_items[ $item->get_order_item_id() ] ) ) { + + /** + * Filter to decide whether to keep non-existing OrderItems within + * the Shipment while validating or not. + * + * @param boolean $keep Whether to keep non-existing OrderItems or not. + * @param ShipmentItem $item The shipment item object. + * @param Shipment $shipment The shipment object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + if ( ! apply_filters( 'woocommerce_gzd_shipment_order_keep_non_order_item', false, $item, $shipment ) ) { + $shipment->remove_item( $item->get_id() ); + } + + continue; + } + + $order_item = $order_items[ $item->get_order_item_id() ]; + $quantity = $this->get_item_quantity_left_for_shipping( + $order_item, + array( + 'shipment_id' => $shipment->get_id(), + 'exclude_current_shipment' => true, + ) + ); + + if ( $quantity <= 0 ) { + $shipment->remove_item( $item->get_id() ); + } else { + $new_quantity = absint( $item->get_quantity() ); + + if ( $item->get_quantity() > $quantity ) { + $new_quantity = $quantity; + } + + $item->sync( array( 'quantity' => $new_quantity ) ); + } + } + + if ( empty( $shipment->get_items() ) ) { + $this->remove_shipment( $shipment->get_id() ); + } + } + } + } + + /** + * @return Shipment[] Shipments + */ + public function get_shipments() { + + if ( is_null( $this->shipments ) ) { + + $this->shipments = wc_gzd_get_shipments( + array( + 'order_id' => $this->get_order()->get_id(), + 'limit' => -1, + 'orderby' => 'date_created', + 'type' => array( 'simple', 'return' ), + 'order' => 'ASC', + ) + ); + } + + $shipments = (array) $this->shipments; + + return $shipments; + } + + /** + * @return SimpleShipment[] + */ + public function get_simple_shipments( $shipped_only = false ) { + $simple = array(); + + foreach ( $this->get_shipments() as $shipment ) { + if ( 'simple' === $shipment->get_type() ) { + if ( $shipped_only && ! $shipment->is_shipped() ) { + continue; + } + + $simple[] = $shipment; + } + } + + return $simple; + } + + /** + * @return ReturnShipment[] + */ + public function get_return_shipments() { + $returns = array(); + + foreach ( $this->get_shipments() as $shipment ) { + if ( 'return' === $shipment->get_type() ) { + $returns[] = $shipment; + } + } + + return $returns; + } + + public function add_shipment( &$shipment ) { + $shipments = $this->get_shipments(); + + $this->shipments[] = $shipment; + } + + public function remove_shipment( $shipment_id ) { + $shipments = $this->get_shipments(); + + foreach ( $this->shipments as $key => $shipment ) { + if ( $shipment->get_id() === (int) $shipment_id ) { + $this->shipments_to_delete[] = $shipment; + + unset( $this->shipments[ $key ] ); + break; + } + } + } + + /** + * @param $shipment_id + * + * @return bool|SimpleShipment|ReturnShipment + */ + public function get_shipment( $shipment_id ) { + $shipments = $this->get_shipments(); + + foreach ( $shipments as $shipment ) { + + if ( $shipment->get_id() === (int) $shipment_id ) { + return $shipment; + } + } + + return false; + } + + /** + * @param WC_Order_Item $order_item + */ + public function get_item_quantity_left_for_shipping( $order_item, $args = array() ) { + $quantity_left = 0; + $args = wp_parse_args( + $args, + array( + 'sent_only' => false, + 'shipment_id' => 0, + 'exclude_current_shipment' => false, + ) + ); + + if ( is_numeric( $order_item ) ) { + $order_item = $this->get_order()->get_item( $order_item ); + } + + if ( $order_item ) { + $quantity_left = $this->get_shippable_item_quantity( $order_item ); + + foreach ( $this->get_shipments() as $shipment ) { + + if ( $args['sent_only'] && ! $shipment->is_shipped() ) { + continue; + } + + if ( $args['exclude_current_shipment'] && $args['shipment_id'] > 0 && ( $shipment->get_id() === $args['shipment_id'] ) ) { + continue; + } + + if ( $item = $shipment->get_item_by_order_item_id( $order_item->get_id() ) ) { + if ( 'return' === $shipment->get_type() ) { + if ( $shipment->is_shipped() ) { + $quantity_left += absint( $item->get_quantity() ); + } + } else { + $quantity_left -= absint( $item->get_quantity() ); + } + } + } + } + + if ( $quantity_left < 0 ) { + $quantity_left = 0; + } + + /** + * Filter to adjust the quantity left for shipment of a specific order item. + * + * @param integer $quantity_left The quantity left for shipment. + * @param WC_Order_Item $order_item The order item object. + * @param Order $this The shipment order object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipment_order_item_quantity_left_for_shipping', $quantity_left, $order_item, $this ); + } + + public function get_item_quantity_sent_by_order_item_id( $order_item_id ) { + $shipments = $this->get_simple_shipments(); + $quantity = 0; + + foreach ( $shipments as $shipment ) { + + if ( ! $shipment->is_shipped() ) { + continue; + } + + if ( $item = $shipment->get_item_by_order_item_id( $order_item_id ) ) { + $quantity += absint( $item->get_quantity() ); + } + } + + return $quantity; + } + + /** + * @param ShipmentItem $item + */ + public function get_item_quantity_left_for_returning( $order_item_id, $args = array() ) { + $quantity_left = 0; + $args = wp_parse_args( + $args, + array( + 'delivered_only' => false, + 'shipment_id' => 0, + 'exclude_current_shipment' => false, + ) + ); + + $quantity_left = $this->get_item_quantity_sent_by_order_item_id( $order_item_id ); + + foreach ( $this->get_return_shipments() as $shipment ) { + + if ( $args['delivered_only'] && ! $shipment->has_status( 'delivered' ) ) { + continue; + } + + if ( $args['exclude_current_shipment'] && $args['shipment_id'] > 0 && ( $shipment->get_id() === $args['shipment_id'] ) ) { + continue; + } + + if ( $shipment_item = $shipment->get_item_by_order_item_id( $order_item_id ) ) { + $quantity_left -= absint( $shipment_item->get_quantity() ); + } + } + + if ( $quantity_left < 0 ) { + $quantity_left = 0; + } + + /** + * Filter to adjust the quantity left for returning of a specific order item. + * + * @param integer $quantity_left The quantity left for shipment. + * @param integer $order_item_id The order item id. + * @param Order $this The shipment order object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipment_order_item_quantity_left_for_returning', $quantity_left, $order_item_id, $this ); + } + + /** + * @param false $group_by_shipping_class + * + * @return OrderItem[] + */ + public function get_items_to_pack_left_for_shipping( $group_by_shipping_class = false ) { + $items = $this->get_available_items_for_shipment(); + $items_to_be_packed = array(); + + foreach ( $items as $order_item_id => $item ) { + if ( ! $order_item = $this->get_order()->get_item( $order_item_id ) ) { + continue; + } + + $shipping_class = ''; + + if ( $group_by_shipping_class ) { + if ( $product = $order_item->get_product() ) { + $shipping_class = $product->get_shipping_class(); + } + } + + for ( $i = 0; $i < $item['max_quantity']; $i++ ) { + try { + $box_item = new Packing\OrderItem( $order_item ); + + if ( ! isset( $items_to_be_packed[ $shipping_class ] ) ) { + $items_to_be_packed[ $shipping_class ] = array(); + } + + $items_to_be_packed[ $shipping_class ][] = $box_item; + } catch ( \Exception $e ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch + } + } + } + + return apply_filters( 'woocommerce_gzd_shipment_order_items_to_pack_left_for_shipping', $items_to_be_packed, $group_by_shipping_class ); + } + + /** + * @param bool|Shipment $shipment + * @return array + */ + public function get_available_items_for_shipment( $args = array() ) { + $args = wp_parse_args( + $args, + array( + 'disable_duplicates' => false, + 'shipment_id' => 0, + 'sent_only' => false, + 'exclude_current_shipment' => false, + ) + ); + + $items = array(); + $shipment = $args['shipment_id'] ? $this->get_shipment( $args['shipment_id'] ) : false; + + foreach ( $this->get_shippable_items() as $item ) { + $quantity_left = $this->get_item_quantity_left_for_shipping( $item, $args ); + + if ( $shipment ) { + if ( $args['disable_duplicates'] && $shipment->get_item_by_order_item_id( $item->get_id() ) ) { + continue; + } + } + + if ( $quantity_left > 0 ) { + $sku = ''; + + if ( is_callable( array( $item, 'get_product' ) ) ) { + if ( $product = $item->get_product() ) { + $sku = $product->get_sku(); + } + } + + $items[ $item->get_id() ] = array( + 'name' => $item->get_name() . ( ! empty( $sku ) ? ' (' . esc_html( $sku ) . ')' : '' ), + 'max_quantity' => $quantity_left, + ); + } + } + + return $items; + } + + /** + * Returns the first found matching shipment item for a certain order item id. + * + * @param $order_item_id + * + * @return bool|ShipmentItem + */ + public function get_simple_shipment_item( $order_item_id ) { + foreach ( $this->get_simple_shipments() as $shipment ) { + + if ( $item = $shipment->get_item_by_order_item_id( $order_item_id ) ) { + return $item; + } + } + + return false; + } + + /** + * @return array + */ + public function get_available_items_for_return( $args = array() ) { + $args = wp_parse_args( + $args, + array( + 'disable_duplicates' => false, + 'shipment_id' => 0, + 'delivered_only' => false, + 'exclude_current_shipment' => false, + ) + ); + + $items = array(); + $shipment = $args['shipment_id'] ? $this->get_shipment( $args['shipment_id'] ) : false; + + foreach ( $this->get_returnable_items() as $item ) { + $quantity_left = $this->get_item_quantity_left_for_returning( $item->get_order_item_id(), $args ); + + if ( $shipment ) { + if ( $args['disable_duplicates'] && $shipment->get_item_by_order_item_id( $item->get_order_item_id() ) ) { + continue; + } + } + + if ( $quantity_left > 0 ) { + $sku = $item->get_sku(); + + $items[ $item->get_order_item_id() ] = array( + 'name' => $item->get_name() . ( ! empty( $sku ) ? ' (' . esc_html( $sku ) . ')' : '' ), + 'max_quantity' => $quantity_left, + ); + } + } + + return $items; + } + + public function item_needs_shipping( $order_item, $args = array() ) { + $args = wp_parse_args( + $args, + array( + 'sent_only' => false, + ) + ); + + $needs_shipping = false; + + if ( $this->get_item_quantity_left_for_shipping( $order_item, $args ) > 0 ) { + $needs_shipping = true; + } + + /** + * Filter to decide whether an order item needs shipping or not. + * + * @param boolean $needs_shipping Whether the item needs shipping or not. + * @param WC_Order_Item $item The order item object. + * @param array $args Additional arguments to be considered. + * @param Order $order The shipment order object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipment_order_item_needs_shipping', $needs_shipping, $order_item, $args, $this ); + } + + /** + * Checks whether an item needs return or not by checking the quantity left for return. + * + * @param ShipmentItem $item + * @param array $args + * + * @return mixed|void + */ + public function item_needs_return( $item, $args = array() ) { + $args = wp_parse_args( + $args, + array( + 'delivered_only' => false, + ) + ); + + $needs_return = false; + + if ( $this->get_item_quantity_left_for_returning( $item->get_order_item_id(), $args ) > 0 ) { + $needs_return = true; + } + + /** + * Filter to decide whether a shipment item needs return or not. + * + * @param boolean $needs_return Whether the item needs return or not. + * @param ShipmentItem $item The order item object. + * @param array $args Additional arguments to be considered. + * @param Order $order The shipment order object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipment_item_needs_return', $needs_return, $item, $args, $this ); + } + + /** + * Returns the return request key added to allow a guest customer to add + * a new return request to a certain order. + * + * @return mixed + */ + public function get_order_return_request_key() { + return $this->get_order()->get_meta( '_return_request_key' ); + } + + /** + * Removes the return request key from the order. Saves the order. + */ + public function delete_order_return_request_key() { + $this->get_order()->delete_meta_data( '_return_request_key' ); + $this->get_order()->save(); + } + + /** + * Returns items that are ready for shipping (defaults to non-virtual line items). + * + * @return WC_Order_Item[] Shippable items. + */ + public function get_shippable_items() { + $items = $this->get_order()->get_items( 'line_item' ); + + foreach ( $items as $key => $item ) { + $product = is_callable( array( $item, 'get_product' ) ) ? $item->get_product() : false; + + if ( $product ) { + if ( $product->is_virtual() || $this->get_shippable_item_quantity( $item ) <= 0 ) { + unset( $items[ $key ] ); + } + } + } + + $items = array_filter( $items ); + + /** + * Filter to adjust shippable order items for a specific order. + * By default excludes virtual items. + * + * @param WC_Order_Item[] $items Array containing shippable order items. + * @param WC_Order $order The order object. + * @param Order $order The shipment order object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipment_order_shippable_items', $items, $this->get_order(), $this ); + } + + /** + * Returns items that are ready for return. By default only shipped (or delivered) items are returnable. + * + * @return ShipmentItem[] Shippable items. + */ + public function get_returnable_items() { + $items = array(); + + foreach ( $this->get_simple_shipments() as $shipment ) { + + if ( ! $shipment->is_shipped() ) { + continue; + } + + foreach ( $shipment->get_items() as $item ) { + + if ( ! isset( $items[ $item->get_order_item_id() ] ) ) { + $new_item = clone $item; + $items[ $item->get_order_item_id() ] = $new_item; + } else { + $new_quantity = absint( $items[ $item->get_order_item_id() ]->get_quantity() ) + absint( $item->get_quantity() ); + $items[ $item->get_order_item_id() ]->set_quantity( $new_quantity ); + } + } + } + + /** + * Filter to adjust returnable items for a specific order. + * + * @param ShipmentItem[] $items Array containing shippable order items. + * @param WC_Order $order The order object. + * @param Order $order The shipment order object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipment_order_returnable_items', $items, $this->get_order(), $this ); + } + + public function get_shippable_item_quantity( $order_item ) { + $refunded_qty = absint( $this->get_order()->get_qty_refunded_for_item( $order_item->get_id() ) ); + + // Make sure we are safe to substract quantity for logical purposes + if ( $refunded_qty < 0 ) { + $refunded_qty *= -1; + } + + $quantity_left = absint( $order_item->get_quantity() ) - $refunded_qty; + + /** + * Filter that allows adjusting the quantity left for shipping or a specific order item. + * + * @param integer $quantity_left The quantity left for shipping. + * @param WC_Order_Item $item The order item object. + * @param Order $order The shipment order object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipment_order_item_shippable_quantity', $quantity_left, $order_item, $this ); + } + + /** + * Returns the total number of shippable items. + * + * @return mixed|void + */ + public function get_shippable_item_count() { + $count = 0; + + foreach ( $this->get_shippable_items() as $item ) { + $count += $this->get_shippable_item_quantity( $item ); + } + + /** + * Filters the total number of shippable items available in an order. + * + * @param integer $count The total number of items. + * @param Order $order The shipment order object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipment_order_shippable_item_count', $count, $this ); + } + + /** + * Returns the number of total returnable items. + * + * @return mixed|void + */ + public function get_returnable_item_count() { + $count = 0; + + foreach ( $this->get_returnable_items() as $item ) { + $count += absint( $item->get_quantity() ); + } + + /** + * Filters the total number of returnable items available in an order. + * + * @param integer $count The total number of items. + * @param Order $order The shipment order object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipment_order_returnable_item_count', $count, $this ); + } + + protected function has_local_pickup() { + $shipping_methods = $this->get_order()->get_shipping_methods(); + $has_pickup = false; + + /** + * Filters which shipping methods are considered local pickup method + * which by default do not require shipment. + * + * @param string[] $pickup_methods Array of local pickup shipping method ids. + * + * @since 3.1.6 + * @package Vendidero/Germanized/Shipments + */ + $pickup_methods = apply_filters( 'woocommerce_gzd_shipment_local_pickup_shipping_methods', array( 'local_pickup' ) ); + + foreach ( $shipping_methods as $shipping_method ) { + if ( in_array( $shipping_method->get_method_id(), $pickup_methods, true ) ) { + $has_pickup = true; + break; + } + } + + return $has_pickup; + } + + /** + * Checks whether the order needs shipping or not by checking quantity + * for every line item. + * + * @param bool $sent_only Whether to only include shipments treated as sent or not. + * + * @return bool Whether the order needs shipping or not. + */ + public function needs_shipping( $args = array() ) { + $args = wp_parse_args( + $args, + array( + 'sent_only' => false, + ) + ); + + $order_items = $this->get_shippable_items(); + $needs_shipping = false; + $has_pickup = $this->has_local_pickup(); + + if ( ! $has_pickup ) { + foreach ( $order_items as $order_item ) { + if ( $this->item_needs_shipping( $order_item, $args ) ) { + $needs_shipping = true; + break; + } + } + } + + /** + * Filter to decide whether an order needs shipping or not. + * + * @param boolean $needs_shipping Whether the order needs shipping or not. + * @param WC_Order $order The order object. + * @param Order $order The shipment order object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipment_order_needs_shipping', $needs_shipping, $this->get_order(), $this ); + } + + /** + * Checks whether the order needs return or not by checking quantity + * for every line item. + * + * @return bool Whether the order needs shipping or not. + */ + public function needs_return( $args = array() ) { + $args = wp_parse_args( + $args, + array( + 'delivered_only' => false, + ) + ); + + $items = $this->get_returnable_items(); + $needs_return = false; + + foreach ( $items as $item ) { + + if ( $this->item_needs_return( $item, $args ) ) { + $needs_return = true; + break; + } + } + + /** + * Filter to decide whether an order needs return or not. + * + * @param boolean $needs_return Whether the order needs return or not. + * @param WC_Order $order The order object. + * @param Order $order The shipment order object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipment_order_needs_return', $needs_return, $this->get_order(), $this ); + } + + public function save() { + if ( ! empty( $this->shipments_to_delete ) ) { + + foreach ( $this->shipments_to_delete as $shipment ) { + $shipment->delete( true ); + } + } + + foreach ( $this->shipments as $shipment ) { + $shipment->save(); + } + } + + /** + * Call child methods if the method does not exist. + * + * @param $method + * @param $args + * + * @return bool|mixed + */ + public function __call( $method, $args ) { + + if ( method_exists( $this->order, $method ) ) { + return call_user_func_array( array( $this->order, $method ), $args ); + } + + return false; + } +} diff --git a/packages/woocommerce-germanized-shipments/src/PDFMerger.php b/packages/woocommerce-germanized-shipments/src/PDFMerger.php new file mode 100644 index 000000000..41131dfc2 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/PDFMerger.php @@ -0,0 +1,142 @@ +_pdf = new Fpdi(); + } + + /** + * Add file to this pdf + * + * @param string $filename Filename of the source file + * @param mixed $pages Range of files (if not set, all pages where imported) + */ + public function add( $filename, $pages = array(), $width = 210 ) { + if ( file_exists( $filename ) ) { + $page_count = $this->_pdf->setSourceFile( $filename ); + + for ( $i = 1; $i <= $page_count; $i ++ ) { + if ( $this->_isPageInRange( $i, $pages ) ) { + $this->_addPage( $i, $width ); + } + } + } + + return $this; + } + + /** + * Output merged pdf + * + * @param string $type + */ + public function output( $filename, $type = 'I' ) { + return $this->_pdf->Output( $type, $filename ); + } + + /** + * Force download merged pdf as file + * + * @param $filename + * + * @return string + */ + public function download( $filename ) { + return $this->output( $filename, 'D' ); + } + + /** + * Save merged pdf + * + * @param $filename + * + * @return string + */ + public function save( $filename ) { + return $this->output( $filename, 'F' ); + } + + /** + * Add single page + * + * @param $page_number + * + * @throws PdfReaderException + */ + private function _addPage( $page_number, $width = 210 ) { // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore,WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid + $page_id = $this->_pdf->importPage( $page_number ); + $size = $this->_pdf->getTemplateSize( $page_id ); + + $orientation = isset( $size['orientation'] ) ? $size['orientation'] : ''; + + $this->_pdf->addPage( $orientation, $size ); + + if ( ! isset( $size['width'] ) || empty( $size['width'] ) ) { + $this->_pdf->useImportedPage( $page_id, 0, 0, $width, null, true ); + } else { + $this->_pdf->useImportedPage( $page_id ); + } + } + + + /** + * Check if a specific page should be merged. + * If pages are empty, all pages will be merged + * + * @return bool + */ + private function _isPageInRange( $page_number, $pages = array() ) { // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore,WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid + if ( empty( $pages ) ) { + return true; + } + + foreach ( $pages as $range ) { + if ( in_array( $page_number, $this->_getRange( $range ), true ) ) { + return true; + } + } + + return false; + } + + + /** + * Get range by given value + * + * @param mixed $value + * + * @return array + */ + private function _getRange( $value = null ) { // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore,WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid + $value = preg_replace( '/[^0-9\-.]/is', '', $value ); + + if ( '' === $value ) { + return false; + } + + $value = explode( '-', $value ); + + if ( 1 === count( $value ) ) { + return $value; + } + + return range( $value[0] > $value[1] ? $value[1] : $value[0], $value[0] > $value[1] ? $value[0] : $value[1] ); + } +} diff --git a/packages/woocommerce-germanized-shipments/src/PDFSplitter.php b/packages/woocommerce-germanized-shipments/src/PDFSplitter.php new file mode 100644 index 000000000..ef518b1dd --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/PDFSplitter.php @@ -0,0 +1,177 @@ +_pdf = new Fpdi(); + + try { + + if ( $stream ) { + $file = StreamReader::createByString( $file ); + $this->filename = $filename; + } else { + $this->filename = basename( $this->file ); + } + + $this->file = $file; + $this->pagecount = $this->_pdf->setSourceFile( $file ); // How many pages? + + } catch ( PdfParserException $e ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch + } catch ( Exception $e ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch + } + } + + public function get_page_count() { + return $this->pagecount; + } + + public function split() { + $new_files = array(); + + try { + // Split each page into a new PDF + for ( $i = 1; $i <= $this->pagecount; $i++ ) { + + $new_pdf = new Fpdi(); + $new_pdf->AddPage(); + $new_pdf->setSourceFile( $this->file ); + $new_pdf->useTemplate( $new_pdf->importPage( $i ), 0, 0, 210, null, true ); + + $new_files[] = $new_pdf->Output( 'S', $this->filename ); + } + } catch ( PdfParserException $e ) { + return false; + } + + return $new_files; + } + + /** + * Add file to this pdf + * + * @param string $filename Filename of the source file + * @param mixed $pages Range of files (if not set, all pages where imported) + */ + public function add( $filename, $pages = array() ) { + if ( file_exists( $filename ) ) { + $page_count = $this->_pdf->setSourceFile( $filename ); + for ( $i = 1; $i <= $page_count; $i++ ) { + if ( $this->_isPageInRange( $i, $pages ) ) { + $this->_addPage( $i ); + } + } + } + return $this; + } + + /** + * Output merged pdf + * + * @param string $type + */ + public function output( $filename, $type = 'I' ) { + return $this->_pdf->Output( $type, $filename ); + } + + /** + * Force download merged pdf as file + * + * @param $filename + * @return string + */ + public function download( $filename ) { + return $this->output( $filename, 'D' ); + } + + /** + * Save merged pdf + * + * @param $filename + * @return string + */ + public function save( $filename ) { + return $this->output( $filename, 'F' ); + } + + /** + * Add single page + * + * @param $page_number + * @throws PdfReaderException + */ + private function _addPage( $page_number ) { // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore,WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid + $page_id = $this->_pdf->importPage( $page_number ); + $this->_pdf->addPage(); + $this->_pdf->useImportedPage( $page_id ); + } + + + /** + * Check if a specific page should be merged. + * If pages are empty, all pages will be merged + * + * @return bool + */ + private function _isPageInRange( $page_number, $pages = array() ) { // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore,WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid + if ( empty( $pages ) ) { + return true; + } + + foreach ( $pages as $range ) { + if ( in_array( $page_number, $this->_getRange( $range ), true ) ) { + return true; + } + } + + return false; + } + + + /** + * Get range by given value + * + * @param mixed $value + * @return array + */ + private function _getRange( $value = null ) { // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore,WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid + $value = preg_replace( '/[^0-9\-.]/is', '', $value ); + + if ( '' === $value ) { + return false; + } + + $value = explode( '-', $value ); + + if ( 1 === count( $value ) ) { + return $value; + } + + return range( $value[0] > $value[1] ? $value[1] : $value[0], $value[0] > $value[1] ? $value[0] : $value[1] ); + } + +} diff --git a/packages/woocommerce-germanized-shipments/src/Package.php b/packages/woocommerce-germanized-shipments/src/Package.php new file mode 100644 index 000000000..121bec72f --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Package.php @@ -0,0 +1,705 @@ +query_vars['add-return-shipment'] ) ) { + $callback = 'woocommerce_gzd_shipments_template_add_return_shipment'; + $order_id = absint( $wp->query_vars['add-return-shipment'] ); + } + + if ( $callback && $order_id && ( $order_shipment = wc_gzd_get_shipment_order( $order_id ) ) && ! empty( $key ) ) { + + // Order return key is invalid. + if ( ! wc_gzd_customer_can_add_return_shipment( $order_id ) ) { + throw new Exception( _x( 'Sorry, this order is invalid and cannot be returned.', 'shipments', 'woocommerce-germanized' ) ); + } else { + call_user_func_array( $callback, array( 'order_id' => $order_id ) ); + $template = self::get_path() . '/templates/global/empty.php'; + } + } + } catch ( Exception $e ) { + wc_add_notice( $e->getMessage(), 'error' ); + } + } + + return $template; + } + + public static function register_shortcodes() { + add_shortcode( 'gzd_return_request_form', array( __CLASS__, 'return_request_form' ) ); + } + + public static function return_request_form( $args = array() ) { + $defaults = array( + 'message' => '', + 'hidden' => false, + ); + + $args = wp_parse_args( $args, $defaults ); + $notices = function_exists( 'wc_print_notices' ) ? wc_print_notices( true ) : ''; + $html = ''; + + // Output notices in case notices have not been outputted yet. + if ( ! empty( $notices ) ) { + $html .= '
' . $notices . '
'; + } + + $html .= wc_get_template_html( 'global/form-return-request.php', $args ); + + return $html; + } + + public static function load_wpml_compatibility( $compatibility ) { + WPMLHelper::init( $compatibility ); + } + + public static function set_method_filters( $methods ) { + foreach ( $methods as $method => $class ) { + add_filter( 'woocommerce_shipping_instance_form_fields_' . $method, array( __CLASS__, 'add_method_settings' ), 10, 1 ); + /** + * Use this filter as a backup to support plugins like Flexible Shipping which may override methods + */ + add_filter( 'woocommerce_settings_api_form_fields_' . $method, array( __CLASS__, 'add_method_settings' ), 10, 1 ); + add_filter( 'woocommerce_shipping_' . $method . '_instance_settings_values', array( __CLASS__, 'filter_method_settings' ), 10, 2 ); + } + + return $methods; + } + + /** + * Indicates whether the BoxPack library for improved packing calculation is supported + * + * @return bool + */ + public static function is_packing_supported() { + return version_compare( phpversion(), '7.1', '>=' ) && apply_filters( 'woocommerce_gzd_enable_rucksack_packaging', true ); + } + + public static function get_method_settings() { + if ( is_null( self::$method_settings ) ) { + self::$method_settings = Method::get_admin_settings(); + } + + return self::$method_settings; + } + + public static function filter_method_settings( $p_settings, $method ) { + $shipping_provider_settings = self::get_method_settings(); + $shipping_provider = isset( $p_settings['shipping_provider'] ) ? $p_settings['shipping_provider'] : ''; + $shipping_method = wc_gzd_get_shipping_provider_method( $method ); + + /** + * Make sure the (maybe) new selected provider is used on updating the settings. + */ + $shipping_method->set_provider( $shipping_provider ); + + foreach ( $p_settings as $setting => $value ) { + if ( array_key_exists( $setting, $shipping_provider_settings ) ) { + // Check if setting does neither belong to global setting nor shipping provider prefix + if ( 'shipping_provider' !== $setting && ! $shipping_method->setting_belongs_to_provider( $setting ) ) { + unset( $p_settings[ $setting ] ); + } elseif ( $shipping_method->get_fallback_setting_value( $setting ) === $value ) { + unset( $p_settings[ $setting ] ); + } elseif ( '' === $value ) { + unset( $p_settings[ $setting ] ); + } + } + } + + /** + * Filter that returns shipping method settings cleaned from global shipping provider method settings. + * This filter might be useful to remove some default setting values from + * shipping provider method settings e.g. DHL settings. + * + * @param array $p_settings The settings + * @param WC_Shipping_Method $method The shipping method instance + * + * @since 3.0.6 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipping_provider_method_clean_settings', $p_settings, $method ); + } + + public static function add_method_settings( $p_settings ) { + $wc = WC(); + + /** + * Prevent undefined index notices during REST API calls. + * + * @see WC_REST_Shipping_Zone_Methods_V2_Controller::get_settings() + */ + if ( is_callable( array( $wc, 'is_rest_api_request' ) ) && $wc->is_rest_api_request() ) { + return $p_settings; + } + + $shipping_provider_settings = self::get_method_settings(); + + return array_merge( $p_settings, $shipping_provider_settings ); + } + + public static function load_shipping_methods( $package ) { + $shipping = WC_Shipping::instance(); + + foreach ( $shipping->shipping_methods as $key => $method ) { + $shipping_provider_method = new Method( $method ); + } + } + + public static function inject_endpoints() { + if ( function_exists( 'WC' ) && WC()->query ) { + foreach ( self::get_endpoints() as $endpoint ) { + if ( ! array_key_exists( $endpoint, WC()->query->query_vars ) ) { + $option_name = str_replace( '-', '_', $endpoint ); + WC()->query->query_vars[ $endpoint ] = get_option( "woocommerce_gzd_shipments_{$option_name}_endpoint", $endpoint ); + } + } + } + } + + public static function get_base_country() { + $default_country = wc_get_base_location()['country']; + $shipment_country = wc_format_country_state_string( self::get_setting( 'shipper_address_country' ) )['country']; + + if ( empty( $shipment_country ) ) { + $shipment_country = $default_country; + } + + return apply_filters( 'woocommerce_gzd_shipment_base_country', $shipment_country ); + } + + public static function get_base_postcode() { + $default_postcode = WC()->countries->get_base_postcode(); + $shipment_postcode = self::get_setting( 'shipper_address_postcode' ); + + if ( empty( $shipment_postcode ) ) { + $shipment_postcode = $default_postcode; + } + + return apply_filters( 'woocommerce_gzd_shipment_base_postcode', $shipment_postcode ); + } + + public static function base_country_belongs_to_eu_customs_area() { + return self::country_belongs_to_eu_customs_area( self::get_base_country(), self::get_base_postcode() ); + } + + public static function country_belongs_to_eu_customs_area( $country, $postcode = '' ) { + $country = wc_strtoupper( $country ); + $eu_countries = WC()->countries->get_european_union_countries(); + $belongs = false; + $postcode = wc_normalize_postcode( $postcode ); + $postcode_wildcards = wc_get_wildcard_postcodes( $postcode, $country ); + + if ( in_array( $country, $eu_countries, true ) ) { + $belongs = true; + } + + if ( $belongs ) { + $exemptions = array( + 'DE' => array( + '27498', // Helgoland + '78266', // Büsingen am Hochrhein + ), + 'ES' => array( + '35*', // Canary Islands + '38*', // Canary Islands + '51*', // Ceuta + '52*', // Melilla + ), + 'GR' => array( + '63086', // Mount Athos + '63087', // Mount Athos + ), + 'IT' => array( + '22060', // Livigno, Campione d’Italia + '23030', // Lake Lugano + ), + 'FI' => array( + 'AX*', // Åland Islands + ), + 'CY' => array( + '9*', // Northern Cyprus + '5*', // Northern Cyprus + ), + ); + + if ( array_key_exists( $country, $exemptions ) ) { + foreach ( $exemptions[ $country ] as $exempt_postcode ) { + if ( in_array( $exempt_postcode, $postcode_wildcards, true ) ) { + $belongs = false; + break; + } + } + } + } + + return apply_filters( 'woocommerce_gzd_country_belongs_to_eu_customs_area', $belongs, $country, $postcode ); + } + + public static function is_shipping_international( $country, $args = array() ) { + $args = self::parse_location_data( $args ); + /** + * In case the sender country belongs to EU customs area, a third country needs to lie outside of the EU customs area + */ + if ( self::country_belongs_to_eu_customs_area( $args['sender_country'], $args['sender_postcode'] ) ) { + if ( ! self::country_belongs_to_eu_customs_area( $country, $args['postcode'] ) ) { + return true; + } + + return false; + } else { + if ( ! self::is_shipping_domestic( $country, $args ) ) { + return true; + } + + return false; + } + } + + public static function is_shipping_domestic( $country, $args = array() ) { + $args = self::parse_location_data( $args ); + $is_domestic = $country === $args['sender_country']; + + /** + * If the sender country belongs to EU customs area but the postcode (e.g. Helgoland in DE) not, do not consider domestic shipping + */ + if ( $is_domestic && self::country_belongs_to_eu_customs_area( $args['sender_country'], $args['sender_postcode'] ) ) { + if ( ! self::country_belongs_to_eu_customs_area( $country, $args['postcode'] ) ) { + $is_domestic = false; + } + } + + return $is_domestic; + } + + private static function parse_location_data( $args = array() ) { + $args = wp_parse_args( + $args, + array( + 'postcode' => '', + 'sender_country' => self::get_base_country(), + 'sender_postcode' => self::get_base_postcode(), + ) + ); + + return $args; + } + + /** + * Whether shipping is inner EU (from one EU country to another) shipment or not. + * + * @param $country + * @param array $args + * + * @return mixed|void + */ + public static function is_shipping_inner_eu_country( $country, $args = array() ) { + $args = self::parse_location_data( $args ); + + if ( self::is_shipping_domestic( $country, $args ) || ! self::country_belongs_to_eu_customs_area( $args['sender_country'], $args['sender_postcode'] ) ) { + return false; + } + + return self::country_belongs_to_eu_customs_area( $country, $args['postcode'] ); + } + + public static function get_endpoints() { + return array( + 'view-shipment', + 'add-return-shipment', + 'view-shipments', + ); + } + + public static function register_endpoints( $query_vars ) { + foreach ( self::get_endpoints() as $endpoint ) { + if ( ! array_key_exists( $endpoint, $query_vars ) ) { + $option_name = str_replace( '-', '_', $endpoint ); + $query_vars[ $endpoint ] = get_option( "woocommerce_gzd_shipments_{$option_name}_endpoint", $endpoint ); + } + } + + return $query_vars; + } + + public static function install() { + self::init(); + Install::install(); + } + + public static function install_integration() { + self::init(); + self::install(); + } + + public static function maybe_set_upload_dir() { + // Create a dir suffix + if ( ! get_option( 'woocommerce_gzd_shipments_upload_dir_suffix', false ) ) { + self::$upload_dir_suffix = substr( self::generate_key(), 0, 10 ); + update_option( 'woocommerce_gzd_shipments_upload_dir_suffix', self::$upload_dir_suffix ); + } else { + self::$upload_dir_suffix = get_option( 'woocommerce_gzd_shipments_upload_dir_suffix' ); + } + } + + /** + * Generate a unique key. + * + * @return string + */ + protected static function generate_key() { + $key = array( ABSPATH, time() ); + $constants = array( 'AUTH_KEY', 'SECURE_AUTH_KEY', 'LOGGED_IN_KEY', 'NONCE_KEY', 'AUTH_SALT', 'SECURE_AUTH_SALT', 'LOGGED_IN_SALT', 'NONCE_SALT', 'SECRET_KEY' ); + + foreach ( $constants as $constant ) { + if ( defined( $constant ) ) { + $key[] = constant( $constant ); + } + } + + shuffle( $key ); + + return md5( serialize( $key ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize + } + + public static function log( $message, $type = 'info' ) { + $enable_logging = defined( 'WP_DEBUG' ) && WP_DEBUG ? true : false; + + /** + * Filter that allows adjusting whether to enable or disable + * logging for the shipments package + * + * @param boolean $enable_logging True if logging should be enabled. False otherwise. + * + * @package Vendidero/Germanized/Shipments + */ + if ( ! apply_filters( 'woocommerce_gzd_shipments_enable_logging', $enable_logging ) ) { + return false; + } + + $logger = wc_get_logger(); + + if ( ! $logger ) { + return false; + } + + if ( ! is_callable( array( $logger, $type ) ) ) { + $type = 'info'; + } + + $logger->{$type}( $message, array( 'source' => 'wc-gzd-shipments' ) ); + } + + public static function get_upload_dir_suffix() { + return self::$upload_dir_suffix; + } + + public static function get_upload_dir() { + + self::set_upload_dir_filter(); + $upload_dir = wp_upload_dir(); + self::unset_upload_dir_filter(); + + /** + * Filter to adjust the upload directory used to store shipment related files. By default + * files are stored in a custom directory under wp-content/uploads. + * + * @param array $upload_dir Array containing `wp_upload_dir` data. + * + * @since 3.0.1 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipments_upload_dir', $upload_dir ); + } + + public static function get_relative_upload_dir( $path ) { + + self::set_upload_dir_filter(); + $path = _wp_relative_upload_path( $path ); + self::unset_upload_dir_filter(); + + /** + * Filter to retrieve the relative upload path used for storing shipment related files. + * + * @param array $path Relative path. + * + * @since 3.0.1 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipments_relative_upload_dir', $path ); + } + + public static function set_upload_dir_filter() { + add_filter( 'upload_dir', array( __CLASS__, 'filter_upload_dir' ), 150, 1 ); + } + + public static function unset_upload_dir_filter() { + remove_filter( 'upload_dir', array( __CLASS__, 'filter_upload_dir' ), 150 ); + } + + public static function get_file_by_path( $file ) { + // If the file is relative, prepend upload dir. + if ( $file && 0 !== strpos( $file, '/' ) && ( ( $uploads = self::get_upload_dir() ) && false === $uploads['error'] ) ) { + $file = $uploads['basedir'] . "/$file"; + + return $file; + } else { + return $file; + } + } + + public static function filter_upload_dir( $args ) { + $upload_base = trailingslashit( $args['basedir'] ); + $upload_url = trailingslashit( $args['baseurl'] ); + + /** + * Filter to adjust the upload path used to store shipment related files. By default + * files are stored in a custom directory under wp-content/uploads. + * + * @param string $path Path to the upload directory. + * + * @since 3.0.6 + * @package Vendidero/Germanized/Shipments + */ + $args['basedir'] = apply_filters( 'woocommerce_gzd_shipments_upload_path', $upload_base . 'wc-gzd-shipments-' . self::get_upload_dir_suffix() ); + /** + * Filter to adjust the upload URL used to retrieve shipment related files. By default + * files are stored in a custom directory under wp-content/uploads. + * + * @param string $url URL to the upload directory. + * + * @since 3.0.6 + * @package Vendidero/Germanized/Shipments + */ + $args['baseurl'] = apply_filters( 'woocommerce_gzd_shipments_upload_url', $upload_url . 'wc-gzd-shipments-' . self::get_upload_dir_suffix() ); + + $args['path'] = $args['basedir'] . $args['subdir']; + $args['url'] = $args['baseurl'] . $args['subdir']; + + return $args; + } + + public static function has_dependencies() { + return class_exists( 'WooCommerce' ) && apply_filters( 'woocommerce_gzd_shipments_enabled', true ); + } + + private static function includes() { + if ( is_admin() ) { + Admin\Admin::init(); + } + + Ajax::init(); + Automation::init(); + Labels\Automation::init(); + Labels\DownloadHandler::init(); + Emails::init(); + Validation::init(); + Api::init(); + FormHandler::init(); + ReportHelper::init(); + + if ( self::is_frontend_request() ) { + include_once self::get_path() . '/includes/wc-gzd-shipment-template-hooks.php'; + } + + include_once self::get_path() . '/includes/wc-gzd-shipment-functions.php'; + include_once self::get_path() . '/includes/wc-gzd-label-functions.php'; + include_once self::get_path() . '/includes/wc-gzd-packaging-functions.php'; + } + + private static function is_frontend_request() { + return ( ! is_admin() || defined( 'DOING_AJAX' ) ) && ! defined( 'DOING_CRON' ); + } + + /** + * Function used to Init WooCommerce Template Functions - This makes them pluggable by plugins and themes. + */ + public static function include_template_functions() { + include_once self::get_path() . '/includes/wc-gzd-shipments-template-functions.php'; + } + + public static function filter_templates( $path, $template_name ) { + + if ( file_exists( self::get_path() . '/templates/' . $template_name ) ) { + $path = self::get_path() . '/templates/' . $template_name; + } + + return $path; + } + + /** + * Register custom tables within $wpdb object. + */ + private static function define_tables() { + global $wpdb; + + // List of tables without prefixes. + $tables = array( + 'gzd_shipment_itemmeta' => 'woocommerce_gzd_shipment_itemmeta', + 'gzd_shipmentmeta' => 'woocommerce_gzd_shipmentmeta', + 'gzd_shipments' => 'woocommerce_gzd_shipments', + 'gzd_shipment_labelmeta' => 'woocommerce_gzd_shipment_labelmeta', + 'gzd_shipment_labels' => 'woocommerce_gzd_shipment_labels', + 'gzd_shipment_items' => 'woocommerce_gzd_shipment_items', + 'gzd_shipping_provider' => 'woocommerce_gzd_shipping_provider', + 'gzd_shipping_providermeta' => 'woocommerce_gzd_shipping_providermeta', + 'gzd_packaging' => 'woocommerce_gzd_packaging', + 'gzd_packagingmeta' => 'woocommerce_gzd_packagingmeta', + ); + + foreach ( $tables as $name => $table ) { + $wpdb->$name = $wpdb->prefix . $table; + $wpdb->tables[] = $table; + } + } + + public static function register_data_stores( $stores ) { + $stores['shipment'] = 'Vendidero\Germanized\Shipments\DataStores\Shipment'; + $stores['shipment-label'] = 'Vendidero\Germanized\Shipments\DataStores\Label'; + $stores['packaging'] = 'Vendidero\Germanized\Shipments\DataStores\Packaging'; + $stores['shipment-item'] = 'Vendidero\Germanized\Shipments\DataStores\ShipmentItem'; + $stores['shipping-provider'] = 'Vendidero\Germanized\Shipments\DataStores\ShippingProvider'; + + do_action( 'woocommerce_gzd_shipments_registered_data_stores' ); + + return $stores; + } + + /** + * Return the version of the package. + * + * @return string + */ + public static function get_version() { + return self::VERSION; + } + + /** + * Return the path to the package. + * + * @return string + */ + public static function get_path() { + return dirname( __DIR__ ); + } + + /** + * Return the path to the package. + * + * @return string + */ + public static function get_url() { + return plugins_url( '', __DIR__ ); + } + + public static function get_assets_url() { + return self::get_url() . '/assets'; + } + + public static function get_setting( $name, $default = false ) { + $option_name = "woocommerce_gzd_shipments_{$name}"; + + return get_option( $option_name, $default ); + } + + public static function get_store_address_country() { + $default = get_option( 'woocommerce_store_country' ); + + return $default; + } + + public static function get_store_address_street() { + $store_address = wc_gzd_split_shipment_street( get_option( 'woocommerce_store_address' ) ); + + return $store_address['street']; + } + + public static function get_store_address_street_number() { + $store_address = wc_gzd_split_shipment_street( get_option( 'woocommerce_store_address' ) ); + + return $store_address['number']; + } + + public static function is_valid_datetime( $maybe_datetime, $format = 'Y-m-d' ) { + if ( ! is_a( $maybe_datetime, 'DateTime' && ! is_numeric( $maybe_datetime ) ) ) { + if ( ! \DateTime::createFromFormat( $format, $maybe_datetime ) ) { + return false; + } + } + + return true; + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Packaging.php b/packages/woocommerce-germanized-shipments/src/Packaging.php new file mode 100644 index 000000000..232881501 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Packaging.php @@ -0,0 +1,339 @@ + null, + 'weight' => 0, + 'max_content_weight' => 0, + 'width' => 0, + 'height' => 0, + 'length' => 0, + 'order' => 0, + 'type' => '', + 'description' => '', + ); + + /** + * Get the packaging if ID is passed, otherwise the packaging is new and empty. + * This class should NOT be instantiated, but the `wc_gzd_get_packaging` function should be used. + * + * @param int|object|Packaging $packaging packaging to read. + */ + public function __construct( $data = 0 ) { + parent::__construct( $data ); + + if ( $data instanceof Packaging ) { + $this->set_id( absint( $data->get_id() ) ); + } elseif ( is_numeric( $data ) ) { + $this->set_id( $data ); + } + + $this->data_store = WC_Data_Store::load( $this->data_store_name ); + + // If we have an ID, load the user from the DB. + if ( $this->get_id() ) { + try { + $this->data_store->read( $this ); + } catch ( Exception $e ) { + $this->set_id( 0 ); + $this->set_object_read( true ); + } + } else { + $this->set_object_read( true ); + } + } + + /** + * Merge changes with data and clear. + * Overrides WC_Data::apply_changes. + * + * @since 3.2.0 + */ + public function apply_changes() { + if ( function_exists( 'array_replace' ) ) { + $this->data = array_replace( $this->data, $this->changes ); // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctions.array_replaceFound + } else { // PHP 5.2 compatibility. + foreach ( $this->changes as $key => $change ) { + $this->data[ $key ] = $change; + } + } + $this->changes = array(); + } + + /** + * Prefix for action and filter hooks on data. + * + * @return string + */ + protected function get_hook_prefix() { + return $this->get_general_hook_prefix() . 'get_'; + } + + /** + * Prefix for action and filter hooks on data. + * + * @return string + */ + protected function get_general_hook_prefix() { + return 'woocommerce_gzd_packaging_'; + } + + /** + * Return the date this packaging was created. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return WC_DateTime|null object if the date is set or null if there is no date. + */ + public function get_date_created( $context = 'view' ) { + return $this->get_prop( 'date_created', $context ); + } + + /** + * Returns the packaging weight in kg. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_weight( $context = 'view' ) { + return $this->get_prop( 'weight', $context ); + } + + /** + * Returns the packaging max content weight in kg. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_max_content_weight( $context = 'view' ) { + return $this->get_prop( 'max_content_weight', $context ); + } + + /** + * Returns the packaging order within its list. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_order( $context = 'view' ) { + return $this->get_prop( 'order', $context ); + } + + /** + * Returns the packaging type e.g. box or letter. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_type( $context = 'view' ) { + return $this->get_prop( 'type', $context ); + } + + /** + * Returns the packaging description. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_description( $context = 'view' ) { + return $this->get_prop( 'description', $context ); + } + + /** + * Returns the packaging length in cm. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_length( $context = 'view' ) { + return $this->get_prop( 'length', $context ); + } + + /** + * Returns the packaging width in cm. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_width( $context = 'view' ) { + return $this->get_prop( 'width', $context ); + } + + /** + * Returns the packaging height in cm. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_height( $context = 'view' ) { + return $this->get_prop( 'height', $context ); + } + + public function has_dimensions() { + $width = $this->get_width(); + $length = $this->get_length(); + $height = $this->get_height(); + + return ( ! empty( $width ) && ! empty( $length ) && ! empty( $height ) ); + } + + /** + * Returns dimensions. + * + * @return string|array + */ + public function get_dimensions() { + return array( + 'length' => wc_format_decimal( $this->get_length(), false, true ), + 'width' => wc_format_decimal( $this->get_width(), false, true ), + 'height' => wc_format_decimal( $this->get_height(), false, true ), + ); + } + + public function get_formatted_dimensions() { + return wc_gzd_format_shipment_dimensions( $this->get_dimensions(), wc_gzd_get_packaging_dimension_unit() ); + } + + public function get_volume() { + return (float) $this->get_length() * (float) $this->get_width() * (float) $this->get_height(); + } + + /** + * Set the date this packaging was created. + * + * @param string|integer|null $date UTC timestamp, or ISO 8601 DateTime. If the DateTime string has no timezone or offset, WordPress site timezone will be assumed. Null if their is no date. + */ + public function set_date_created( $date = null ) { + $this->set_date_prop( 'date_created', $date ); + } + + /** + * Set packaging weight in kg. + * + * @param string $weight The weight. + */ + public function set_weight( $weight ) { + $this->set_prop( 'weight', empty( $weight ) ? 0 : wc_format_decimal( $weight, 2, true ) ); + } + + public function get_title() { + $description = $this->get_description(); + + return sprintf( + _x( '%1$s (%2$s, %3$s)', 'shipments-packaging-title', 'woocommerce-germanized' ), + $description, + $this->get_formatted_dimensions(), + wc_gzd_format_shipment_weight( wc_format_decimal( $this->get_weight(), false, true ), wc_gzd_get_packaging_weight_unit() ) + ); + } + + /** + * Set packaging order. + * + * @param integer $order The order. + */ + public function set_order( $order ) { + $this->set_prop( 'order', absint( $order ) ); + } + + /** + * Set packaging max content weight in kg. + * + * @param string $weight The weight. + */ + public function set_max_content_weight( $weight ) { + $this->set_prop( 'max_content_weight', empty( $weight ) ? 0 : wc_format_decimal( $weight, 2, true ) ); + } + + /** + * Set packaging type + * + * @param string $type The type. + */ + public function set_type( $type ) { + $this->set_prop( 'type', $type ); + } + + /** + * Set packaging description + * + * @param string $description The description. + */ + public function set_description( $description ) { + $this->set_prop( 'description', $description ); + } + + /** + * Set packaging width in cm. + * + * @param string $width The width. + */ + public function set_width( $width ) { + $this->set_prop( 'width', empty( $width ) ? 0 : wc_format_decimal( $width, 1, true ) ); + } + + /** + * Set packaging length in cm. + * + * @param string $length The length. + */ + public function set_length( $length ) { + $this->set_prop( 'length', empty( $length ) ? 0 : wc_format_decimal( $length, 1, true ) ); + } + + /** + * Set packaging height in cm. + * + * @param string $height The height. + */ + public function set_height( $height ) { + $this->set_prop( 'height', empty( $height ) ? 0 : wc_format_decimal( $height, 1, true ) ); + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Packaging/AsyncReportGenerator.php b/packages/woocommerce-germanized-shipments/src/Packaging/AsyncReportGenerator.php new file mode 100644 index 000000000..b275237a8 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Packaging/AsyncReportGenerator.php @@ -0,0 +1,164 @@ +type = $type; + $default_end = new \WC_DateTime(); + $default_start = new \WC_DateTime( 'now' ); + $default_start->modify( '-1 year' ); + + $args = wp_parse_args( + $args, + array( + 'start' => $default_start->format( 'Y-m-d' ), + 'end' => $default_end->format( 'Y-m-d' ), + 'limit' => ReportQueue::get_batch_size(), + 'status' => ReportQueue::get_shipment_statuses(), + 'offset' => 0, + 'type' => array( 'simple', 'return' ), + 'processed' => 0, + ) + ); + + foreach ( array( 'start', 'end' ) as $date_field ) { + if ( is_a( $args[ $date_field ], 'WC_DateTime' ) ) { + $args[ $date_field ] = $args[ $date_field ]->format( 'Y-m-d' ); + } elseif ( is_numeric( $args[ $date_field ] ) ) { + $date = new \WC_DateTime( '@' . $args[ $date_field ] ); + $args[ $date_field ] = $date->format( 'Y-m-d' ); + } + } + + $this->args = $args; + } + + public function get_type() { + return $this->type; + } + + public function get_args() { + return $this->args; + } + + public function get_id() { + return ReportHelper::get_report_id( + array( + 'type' => $this->type, + 'date_start' => $this->args['start'], + 'date_end' => $this->args['end'], + ) + ); + } + + public function delete() { + $report = new Report( $this->get_id() ); + $report->delete(); + + delete_option( $this->get_id() . '_tmp_result' ); + } + + public function start() { + $report = new Report( $this->get_id() ); + $report->reset(); + $report->save(); + + return $report; + } + + /** + * @return true|\WP_Error + */ + public function next() { + $args = $this->args; + $shipments = ReportQueue::query( $args ); + $shipments_processed = 0; + $packaging_data = $this->get_temporary_result(); + + Package::log( sprintf( '%d applicable shipments found', count( $shipments ) ) ); + + if ( ! empty( $shipments ) ) { + foreach ( $shipments as $shipment ) { + $packaging_weight = $shipment->get_packaging_weight(); + $packaging = $shipment->get_packaging(); + $packaging_id = 'other'; + + if ( ! $shipment->get_packaging_weight() ) { + Package::log( sprintf( 'Skipping shipment #%1$s due to missing packaging weight.', $shipment->get_id() ) ); + continue; + } + + if ( $packaging ) { + $packaging_id = $packaging->get_id(); + } + + if ( ! isset( $packaging_data[ "$packaging_id" ] ) ) { + $packaging_data[ "$packaging_id" ] = array( + 'count' => 0, + 'weight_in_kg' => 0.0, + ); + } + + $packaging_data[ "$packaging_id" ]['count'] += 1; + $packaging_data[ "$packaging_id" ]['weight_in_kg'] += wc_add_number_precision( (float) wc_get_weight( $packaging_weight, 'kg', $shipment->get_weight_unit() ), false ); + + $shipments_processed++; + } + + $this->args['processed'] = absint( $this->args['processed'] ) + $shipments_processed; + + update_option( $this->get_id() . '_tmp_result', $packaging_data, false ); + + return true; + } else { + return new \WP_Error( 'empty', _x( 'No shipments found.', 'shipments', 'woocommerce-germanized' ) ); + } + } + + /** + * @return Report + */ + public function complete() { + Package::log( sprintf( 'Completed called' ) ); + + $tmp_result = $this->get_temporary_result(); + $report = new Report( $this->get_id() ); + $count_total = 0; + $weight_total = 0.0; + + foreach ( $tmp_result as $packaging_id => $totals ) { + $count_total += (int) $totals['count']; + $weight_total += (float) $totals['weight_in_kg']; + + $report->set_packaging_count( $packaging_id, (int) $totals['count'] ); + $report->set_packaging_weight( $packaging_id, (float) wc_remove_number_precision( $totals['weight_in_kg'] ) ); + } + + $weight_total = (float) wc_remove_number_precision( $weight_total ); + + Package::log( sprintf( 'Completed packaging count: %d', $count_total ) ); + Package::log( sprintf( 'Completed packaging weight: %s', $weight_total ) ); + + $report->set_total_count( $count_total ); + $report->set_total_weight( $weight_total ); + $report->set_status( 'completed' ); + $report->set_version( Package::get_version() ); + $report->save(); + + return $report; + } + + protected function get_temporary_result() { + return (array) get_option( $this->get_id() . '_tmp_result', array() ); + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Packaging/Report.php b/packages/woocommerce-germanized-shipments/src/Packaging/Report.php new file mode 100644 index 000000000..a1d9f063e --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Packaging/Report.php @@ -0,0 +1,310 @@ +set_id( $id ); + + if ( empty( $args ) ) { + $args = (array) get_option( $this->id . '_result', array() ); + } + + $args = wp_parse_args( + $args, + array( + 'packaging' => array(), + 'totals' => array(), + 'meta' => array(), + ) + ); + + $args['totals'] = wp_parse_args( + $args['totals'], + array( + 'weight_in_kg' => 0.0, + 'count' => 0, + ) + ); + + $args['meta'] = wp_parse_args( + $args['meta'], + array( + 'date_requested' => null, + 'status' => 'pending', + 'version' => '', + ) + ); + + $this->set_date_requested( $args['meta']['date_requested'] ); + $this->set_status( $args['meta']['status'] ); + $this->set_version( $args['meta']['version'] ); + + $this->args = $args; + } + + public function exists() { + return get_option( $this->id . '_result', false ); + } + + public function get_title() { + $title = ReportHelper::get_report_title( $this->get_id() ); + + if ( $this->get_date_requested() ) { + $title = $title . ' @ ' . $this->get_date_requested()->date_i18n(); + } + + return $title; + } + + public function get_url() { + return admin_url( 'admin.php?page=shipment-packaging-report&report=' . $this->get_id() ); + } + + public function get_delete_link() { + return add_query_arg( + array( + 'action' => 'wc_gzd_shipments_packaging_delete_report', + 'report_id' => $this->get_id(), + ), + wp_nonce_url( admin_url( 'admin-post.php' ), 'wc_gzd_shipments_packaging_delete_report' ) + ); + } + + public function get_refresh_link() { + return add_query_arg( + array( + 'action' => 'wc_gzd_shipments_packaging_refresh_report', + 'report_id' => $this->get_id(), + ), + wp_nonce_url( admin_url( 'admin-post.php' ), 'wc_gzd_shipments_packaging_refresh_report' ) + ); + } + + public function get_cancel_link() { + return add_query_arg( + array( + 'action' => 'wc_gzd_shipments_packaging_cancel_report', + 'report_id' => $this->get_id(), + ), + wp_nonce_url( admin_url( 'admin-post.php' ), 'wc_gzd_shipments_packaging_cancel_report' ) + ); + } + + public function get_type() { + return $this->type; + } + + public function set_type( $type ) { + $this->set_id_part( $type, 'type' ); + } + + public function set_id( $id ) { + $this->id = $id; + $data = ReportHelper::get_report_data( $this->id ); + $this->type = $data['type']; + $this->date_start = $data['date_start']; + $this->date_end = $data['date_end']; + } + + public function set_id_part( $value, $part = 'type' ) { + $data = ReportHelper::get_report_data( $this->id ); + $data[ $part ] = $value; + + $this->set_id( ReportHelper::get_report_id( $data ) ); + } + + public function get_id() { + return $this->id; + } + + public function get_date_start() { + return $this->date_start; + } + + public function set_date_start( $date ) { + $date = ReportHelper::string_to_datetime( $date ); + + $this->set_id_part( $date->format( 'Y-m-d' ), 'date_start' ); + } + + public function get_date_end() { + return $this->date_end; + } + + public function set_date_end( $date ) { + $date = ReportHelper::string_to_datetime( $date ); + + $this->set_id_part( $date->format( 'Y-m-d' ), 'date_end' ); + } + + public function get_status() { + return $this->args['meta']['status']; + } + + public function get_version() { + return $this->args['meta']['version']; + } + + public function set_status( $status ) { + $this->args['meta']['status'] = $status; + } + + public function set_version( $version ) { + $this->args['meta']['version'] = $version; + } + + public function get_date_requested() { + return is_null( $this->args['meta']['date_requested'] ) ? null : ReportHelper::string_to_datetime( $this->args['meta']['date_requested'] ); + } + + public function set_date_requested( $date ) { + if ( ! empty( $date ) ) { + $date = ReportHelper::string_to_datetime( $date ); + } + + $this->args['meta']['date_requested'] = is_a( $date, 'WC_DateTime' ) ? $date->date( 'Y-m-d' ) : null; + } + + /** + * @return int + */ + public function get_total_count() { + return (int) $this->args['totals']['count']; + } + + public function get_total_weight( $round = true, $unit = '' ) { + if ( '' === $unit ) { + $unit = wc_gzd_get_packaging_weight_unit(); + } + + $weight = wc_get_weight( $this->args['totals']['weight_in_kg'], $unit, 'kg' ); + + return $this->maybe_round( $weight, $round ); + } + + public function set_total_weight( $weight ) { + $this->args['totals']['weight_in_kg'] = wc_format_decimal( floatval( $weight ) ); + } + + public function set_total_count( $count ) { + $this->args['totals']['count'] = absint( $count ); + } + + public function get_packaging_ids() { + return array_keys( $this->args['packaging'] ); + } + + public function reset() { + $this->args['packaging'] = array(); + + $this->set_total_count( 0 ); + $this->set_total_weight( 0 ); + $this->set_date_requested( new \WC_DateTime() ); + $this->set_status( 'pending' ); + $this->set_version( Package::get_version() ); + + delete_option( $this->id . '_tmp_result' ); + } + + public function get_packaging_count( $packaging_id ) { + $count = 0; + + if ( isset( $this->args['packaging'][ "$packaging_id" ] ) ) { + $count = absint( $this->args['packaging'][ "$packaging_id" ]['count'] ); + } + + return $count; + } + + public function get_packaging_weight( $packaging_id, $round = true, $unit = '' ) { + $weight = 0.0; + + if ( isset( $this->args['packaging'][ "$packaging_id" ] ) ) { + $weight = $this->args['packaging'][ "$packaging_id" ]['weight_in_kg']; + } + + $weight = wc_get_weight( $weight, $unit, 'kg' ); + + return $this->maybe_round( $weight, $round ); + } + + public function set_packaging_count( $packaging_id, $count ) { + if ( ! isset( $this->args['packaging'][ "$packaging_id" ] ) ) { + $this->args['packaging'][ "$packaging_id" ] = array( + 'count' => 0, + 'weight_in_kg' => 0.0, + ); + } + + $this->args['packaging'][ "$packaging_id" ]['count'] = absint( $count ); + } + + public function set_packaging_weight( $packaging_id, $weight ) { + if ( ! isset( $this->args['packaging'][ "$packaging_id" ] ) ) { + $this->args['packaging'][ "$packaging_id" ] = array( + 'count' => 0, + 'weight_in_kg' => 0.0, + ); + } + + $this->args['packaging'][ "$packaging_id" ]['weight_in_kg'] = (float) wc_format_decimal( $weight ); + } + + protected function maybe_round( $total, $round = true ) { + $decimals = is_numeric( $round ) ? (int) $round : ''; + + return (float) wc_format_decimal( $total, $round ? $decimals : false ); + } + + public function save() { + update_option( $this->id . '_result', $this->args, false ); + + $reports_available = ReportHelper::get_report_ids(); + + if ( ! in_array( $this->get_id(), $reports_available[ $this->get_type() ], true ) ) { + // Add new report to start of the list + array_unshift( $reports_available[ $this->get_type() ], $this->get_id() ); + update_option( 'woocommerce_gzd_shipments_packaging_reports', $reports_available, false ); + } + + delete_option( $this->id . '_tmp_result' ); + + ReportHelper::clear_caches(); + + return $this->id; + } + + public function delete() { + delete_option( $this->id . '_result' ); + delete_option( $this->id . '_tmp_result' ); + + ReportQueue::maybe_stop_report( $this->get_id() ); + ReportHelper::remove_report( $this ); + + ReportHelper::clear_caches(); + + return true; + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Packaging/ReportHelper.php b/packages/woocommerce-germanized-shipments/src/Packaging/ReportHelper.php new file mode 100644 index 000000000..c58ed49eb --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Packaging/ReportHelper.php @@ -0,0 +1,487 @@ + array( + 'url' => $report->get_url(), + 'title' => _x( 'View', 'shipments-packaging-report', 'woocommerce-germanized' ), + ), + 'refresh' => array( + 'url' => $report->get_refresh_link(), + 'title' => _x( 'Refresh', 'shipments-packaging-report', 'woocommerce-germanized' ), + ), + 'delete' => array( + 'url' => $report->get_delete_link(), + 'title' => _x( 'Delete', 'shipments-packaging-report', 'woocommerce-germanized' ), + ), + ); + + if ( 'completed' !== $report->get_status() ) { + $actions['cancel'] = $actions['delete']; + $actions['cancel']['title'] = _x( 'Cancel', 'shipments-packaging-report', 'woocommerce-germanized' ); + + unset( $actions['view'] ); + unset( $actions['refresh'] ); + unset( $actions['delete'] ); + } + + return $actions; + } + + public static function render_report() { + if ( isset( $_GET['report'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $report_id = isset( $_GET['report'] ) ? wc_clean( wp_unslash( $_GET['report'] ) ) : false; // phpcs:ignore WordPress.Security.NonceVerification.Recommended + + if ( ! $report_id ) { + return; + } + + if ( ! $report = self::get_report( $report_id ) ) { + return; + } + + $columns = array( + 'packaging' => _x( 'Packaging', 'shipments', 'woocommerce-germanized' ), + 'weight' => _x( 'Weight', 'shipments', 'woocommerce-germanized' ), + 'count' => _x( 'Count', 'shipments', 'woocommerce-germanized' ), + ); + + $packaging_ids = $report->get_packaging_ids(); + $actions = self::get_report_actions( $report ); + ?> +
+

get_title() ); ?>

+ + $action ) : + if ( 'view' === $action_type ) { + continue; + } + ?> + + + + get_status() ) : ?> +

get_date_start()->date_i18n( wc_date_format() ) ); ?> – get_date_end()->date_i18n( wc_date_format() ) ); ?>: get_total_weight(), wc_gzd_get_packaging_weight_unit() ) ); ?> (get_total_count() ) ); ?>)

+
+ + + + + $column ) : ?> + + + + + + + + + + + + + +
get_id() > 0 ? $packaging->get_description() : _x( 'Unknown', 'shipments-packaging-title', 'woocommerce-germanized' ) ) ); ?>get_packaging_weight( $packaging_id ), wc_gzd_get_packaging_weight_unit() ) ); ?>get_packaging_count( $packaging_id ) ); ?>
+ + +

Find pending actions', 'shipments', 'woocommerce-germanized' ), esc_html( $details['shipment_count'] ), ( $details['next_date'] ? esc_html( $details['next_date']->date_i18n( wc_date_format() . ' @ ' . wc_time_format() ) ) : esc_html_x( 'Not yet known', 'shipments', 'woocommerce-germanized' ) ), esc_url( $details['link'] ) ); ?>

+ +
+ get_status() ) { + $report->delete(); + } + } + } + } + + $running = array_values( $running ); + + update_option( 'woocommerce_gzd_shipments_packaging_reports_running', $running, false ); + ReportQueue::clear_cache(); + } + + public static function setup_recurring_actions() { + if ( $queue = ReportQueue::get_queue() ) { + // Schedule once per day at 2:00 + if ( null === $queue->get_next( 'woocommerce_gzd_shipments_daily_cleanup', array(), 'woocommerce_gzd_shipments' ) ) { + $timestamp = strtotime( 'tomorrow midnight' ); + $date = new \WC_DateTime(); + + $date->setTimestamp( $timestamp ); + $date->modify( '+2 hours' ); + + $queue->cancel_all( 'woocommerce_gzd_shipments_daily_cleanup', array(), 'woocommerce_gzd_shipments' ); + $queue->schedule_recurring( $date->getTimestamp(), DAY_IN_SECONDS, 'woocommerce_gzd_shipments_daily_cleanup', array(), 'woocommerce_gzd_shipments' ); + } + } + } + + public static function get_report_title( $id ) { + $args = self::get_report_data( $id ); + $title = _x( 'Report', 'shipments', 'woocommerce-germanized' ); + + if ( 'quarterly' === $args['type'] ) { + $date_start = $args['date_start']; + $quarter = 1; + $month_num = (int) $date_start->date_i18n( 'n' ); + + if ( 4 === $month_num ) { + $quarter = 2; + } elseif ( 7 === $month_num ) { + $quarter = 3; + } elseif ( 10 === $month_num ) { + $quarter = 4; + } + + $title = sprintf( _x( 'Q%1$s/%2$s', 'shipments', 'woocommerce-germanized' ), $quarter, $date_start->date_i18n( 'Y' ) ); + } elseif ( 'monthly' === $args['type'] ) { + $date_start = $args['date_start']; + $month_num = $date_start->date_i18n( 'm' ); + + $title = sprintf( _x( '%1$s/%2$s', 'shipments', 'woocommerce-germanized' ), $month_num, $date_start->date_i18n( 'Y' ) ); + } elseif ( 'yearly' === $args['type'] ) { + $date_start = $args['date_start']; + + $title = sprintf( _x( '%1$s', 'shipments', 'woocommerce-germanized' ), $date_start->date_i18n( 'Y' ) ); // phpcs:ignore WordPress.WP.I18n.NoEmptyStrings + } elseif ( 'custom' === $args['type'] ) { + $date_start = $args['date_start']; + $date_end = $args['date_end']; + + $title = sprintf( _x( '%1$s - %2$s', 'shipments', 'woocommerce-germanized' ), $date_start->date_i18n( 'Y-m-d' ), $date_end->date_i18n( 'Y-m-d' ) ); + } + + return $title; + } + + public static function get_report_id( $parts ) { + $parts = wp_parse_args( + $parts, + array( + 'type' => 'daily', + 'date_start' => date( 'Y-m-d' ), // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date + 'date_end' => date( 'Y-m-d' ), // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date + ) + ); + + if ( is_a( $parts['date_start'], 'WC_DateTime' ) ) { + $parts['date_start'] = $parts['date_start']->format( 'Y-m-d' ); + } + + if ( is_a( $parts['date_end'], 'WC_DateTime' ) ) { + $parts['date_end'] = $parts['date_end']->format( 'Y-m-d' ); + } + + return sanitize_key( 'woocommerce_gzd_shipments_packaging_' . $parts['type'] . '_report_' . $parts['date_start'] . '_' . $parts['date_end'] ); + } + + public static function get_available_report_types() { + $types = array( + 'quarterly' => _x( 'Quarterly', 'shipments', 'woocommerce-germanized' ), + 'yearly' => _x( 'Yearly', 'shipments', 'woocommerce-germanized' ), + 'monthly' => _x( 'Monthly', 'shipments', 'woocommerce-germanized' ), + 'custom' => _x( 'Custom', 'shipments', 'woocommerce-germanized' ), + ); + + return $types; + } + + public static function get_report_data( $id ) { + $clean_id = str_replace( 'packaging_', '', $id ); + $clean_id = str_replace( 'woocommerce_gzd_shipments_', '', $clean_id ); + $id_parts = explode( '_', $clean_id ); + + $data = array( + 'id' => $id, + 'type' => $id_parts[0], + 'date_start' => self::string_to_datetime( $id_parts[2] ), + 'date_end' => self::string_to_datetime( $id_parts[3] ), + ); + + return $data; + } + + public static function string_to_datetime( $time_string ) { + if ( is_string( $time_string ) && ! is_numeric( $time_string ) ) { + $time_string = strtotime( $time_string ); + } + + $date_time = $time_string; + + if ( is_numeric( $date_time ) ) { + $date_time = new \WC_DateTime( "@{$date_time}", new \DateTimeZone( 'UTC' ) ); + } + + if ( ! is_a( $date_time, 'WC_DateTime' ) ) { + return null; + } + + return $date_time; + } + + public static function clear_caches() { + delete_transient( 'woocommerce_gzd_shipments_packaging_report_counts' ); + wp_cache_delete( 'woocommerce_gzd_shipments_packaging_reports', 'options' ); + } + + public static function get_report_ids() { + $reports = (array) get_option( 'woocommerce_gzd_shipments_packaging_reports', array() ); + + foreach ( array_keys( self::get_available_report_types() ) as $type ) { + if ( ! array_key_exists( $type, $reports ) ) { + $reports[ $type ] = array(); + } + } + + return $reports; + } + + public static function get_report_status_title( $status ) { + if ( 'completed' === $status ) { + return _x( 'Completed', 'shipments-report-status', 'woocommerce-germanized' ); + } else { + return _x( 'Pending', 'shipments-report-status', 'woocommerce-germanized' ); + } + } + + /** + * @param array $args + * + * @return Report[] + */ + public static function get_reports( $args = array() ) { + $args = wp_parse_args( + $args, + array( + 'type' => '', + 'limit' => -1, + 'offset' => 0, + 'orderby' => 'date_start', + ) + ); + + $ids = self::get_report_ids(); + + if ( ! empty( $args['type'] ) ) { + $report_ids = array_key_exists( $args['type'], $ids ) ? $ids[ $args['type'] ] : array(); + } else { + $report_ids = array_merge( ...array_values( $ids ) ); + } + + $reports_sorted = array(); + + foreach ( $report_ids as $id ) { + $reports_sorted[] = self::get_report_data( $id ); + } + + if ( array_key_exists( $args['orderby'], array( 'date_start', 'date_end' ) ) ) { + usort( + $reports_sorted, + function( $a, $b ) use ( $args ) { + if ( $a[ $args['orderby'] ] === $b[ $args['orderby'] ] ) { + return 0; + } + + return $a[ $args['orderby'] ] < $b[ $args['orderby'] ] ? -1 : 1; + } + ); + } + + if ( -1 !== $args['limit'] ) { + $reports_sorted = array_slice( $reports_sorted, $args['offset'], $args['limit'] ); + } + + $reports = array(); + + foreach ( $reports_sorted as $data ) { + if ( $report = self::get_report( $data['id'] ) ) { + $reports[] = $report; + } + } + + return $reports; + } + + /** + * @param Report $report + */ + public static function remove_report( $report ) { + $reports_available = self::get_report_ids(); + + if ( in_array( $report->get_id(), $reports_available[ $report->get_type() ], true ) ) { + $reports_available[ $report->get_type() ] = array_diff( $reports_available[ $report->get_type() ], array( $report->get_id() ) ); + + update_option( 'woocommerce_gzd_shipments_packaging_reports', $reports_available, false ); + + /** + * Force non-cached option + */ + wp_cache_delete( 'woocommerce_gzd_shipments_packaging_reports', 'options' ); + } + } + + /** + * @param $id + * + * @return false|Report + */ + public static function get_report( $id ) { + $report = new Report( $id ); + + if ( $report->exists() ) { + return $report; + } + + return false; + } + + public static function delete_report() { + if ( ! current_user_can( 'manage_woocommerce' ) || ! wp_verify_nonce( isset( $_GET['_wpnonce'] ) ? wp_unslash( $_GET['_wpnonce'] ) : '', 'wc_gzd_shipments_packaging_delete_report' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + wp_die(); + } + + $report_id = isset( $_GET['report_id'] ) ? wc_clean( wp_unslash( $_GET['report_id'] ) ) : ''; + + if ( ! empty( $report_id ) && ( $report = self::get_report( $report_id ) ) ) { + $report->delete(); + + $referer = self::get_clean_referer(); + + /** + * Do not redirect deleted, refreshed reports back to report details page + */ + if ( strstr( $referer, '&report=' ) ) { + $referer = admin_url( 'admin.php?page=wc-settings&tab=germanized-shipments§ion=packaging' ); + } + + wp_safe_redirect( esc_url_raw( add_query_arg( array( 'report_deleted' => $report_id ), $referer ) ) ); + exit(); + } + + wp_safe_redirect( esc_url_raw( wp_get_referer() ) ); + exit(); + } + + protected static function get_clean_referer() { + $referer = wp_get_referer(); + + return remove_query_arg( array( 'report_created', 'report_deleted', 'report_restarted', 'report_cancelled' ), $referer ); + } + + public static function refresh_report() { + if ( ! current_user_can( 'manage_woocommerce' ) || ! wp_verify_nonce( isset( $_GET['_wpnonce'] ) ? wp_unslash( $_GET['_wpnonce'] ) : '', 'wc_gzd_shipments_packaging_refresh_report' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + wp_die(); + } + + $report_id = isset( $_GET['report_id'] ) ? wc_clean( wp_unslash( $_GET['report_id'] ) ) : ''; + + if ( ! empty( $report_id ) && ( $report = self::get_report( $report_id ) ) ) { + ReportQueue::start( $report->get_type(), $report->get_date_start(), $report->get_date_end() ); + + wp_safe_redirect( esc_url_raw( add_query_arg( array( 'report_restarted' => $report_id ), self::get_clean_referer() ) ) ); + exit(); + } + + wp_safe_redirect( esc_url_raw( wp_get_referer() ) ); + exit(); + } + + public static function cancel_report() { + if ( ! current_user_can( 'manage_woocommerce' ) || ! wp_verify_nonce( isset( $_GET['_wpnonce'] ) ? wp_unslash( $_GET['_wpnonce'] ) : '', 'wc_gzd_shipments_packaging_cancel_report' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + wp_die(); + } + + $report_id = isset( $_GET['report_id'] ) ? wc_clean( wp_unslash( $_GET['report_id'] ) ) : ''; + + if ( ! empty( $report_id ) && ReportQueue::is_running( $report_id ) ) { + ReportQueue::cancel( $report_id ); + + $referer = self::get_clean_referer(); + + /** + * Do not redirect deleted, refreshed reports back to report details page + */ + if ( strstr( $referer, '&report=' ) ) { + $referer = admin_url( 'admin.php?page=wc-settings&tab=germanized-shipments§ion=packaging' ); + } + + wp_safe_redirect( esc_url_raw( add_query_arg( array( 'report_cancelled' => $report_id ), $referer ) ) ); + exit(); + } + + wp_safe_redirect( esc_url_raw( wp_get_referer() ) ); + exit(); + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Packaging/ReportQueue.php b/packages/woocommerce-germanized-shipments/src/Packaging/ReportQueue.php new file mode 100644 index 000000000..3d27f83c1 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Packaging/ReportQueue.php @@ -0,0 +1,337 @@ +diff( $args['end'] ); + + // Add version + $args['version'] = Package::get_version(); + + $generator = new AsyncReportGenerator( $type, $args ); + $queue_args = $generator->get_args(); + $queue = self::get_queue(); + + self::cancel( $generator->get_id() ); + + $report = $generator->start(); + + if ( is_a( $report, '\Vendidero\Germanized\Shipments\Packaging\Report' ) && $report->exists() ) { + Package::log( sprintf( 'Starting new %1$s', $report->get_title() ) ); + Package::log( sprintf( 'Default report arguments: %s', wc_print_r( $queue_args, true ) ) ); + + $queue->schedule_single( + time() + 10, + self::get_hook_name( $generator->get_id() ), + array( 'args' => $queue_args ), + 'woocommerce_gzd_shipments' + ); + + $running = self::get_reports_running(); + + if ( ! in_array( $generator->get_id(), $running, true ) ) { + $running[] = $generator->get_id(); + } + + update_option( 'woocommerce_gzd_shipments_packaging_reports_running', $running, false ); + self::clear_cache(); + + return $generator->get_id(); + } + + return false; + } + + public static function clear_cache() { + wp_cache_delete( 'woocommerce_gzd_shipments_packaging_reports_running', 'options' ); + } + + public static function get_queue_details( $report_id ) { + $details = array( + 'next_date' => null, + 'link' => admin_url( 'admin.php?page=wc-status&tab=action-scheduler&s=' . esc_attr( $report_id ) . '&status=pending' ), + 'shipment_count' => 0, + 'has_action' => false, + 'is_finished' => false, + 'action' => false, + ); + + if ( $queue = self::get_queue() ) { + if ( $next_date = $queue->get_next( self::get_hook_name( $report_id ) ) ) { + $details['next_date'] = $next_date; + } + + $search_args = array( + 'hook' => self::get_hook_name( $report_id ), + 'status' => \ActionScheduler_Store::STATUS_RUNNING, + 'order' => 'DESC', + 'per_page' => 1, + ); + + $results = $queue->search( $search_args ); + + /** + * Search for pending as fallback + */ + if ( empty( $results ) ) { + $search_args['status'] = \ActionScheduler_Store::STATUS_PENDING; + $results = $queue->search( $search_args ); + } + + /** + * Last resort: Search for completed (e.g. if no pending and no running are found - must have been completed) + */ + if ( empty( $results ) ) { + $search_args['status'] = \ActionScheduler_Store::STATUS_COMPLETE; + $results = $queue->search( $search_args ); + } + + if ( ! empty( $results ) ) { + $action = array_values( $results )[0]; + $args = $action->get_args(); + $processed = isset( $args['args']['shipments_processed'] ) ? (int) $args['args']['shipments_processed'] : 0; + + $details['shipment_count'] = absint( $processed ); + $details['has_action'] = true; + $details['action'] = $action; + $details['is_finished'] = $action->is_finished(); + } + } + + return $details; + } + + public static function get_batch_size() { + return apply_filters( 'woocommerce_gzd_shipments_packaging_report_batch_size', 25 ); + } + + public static function get_shipment_statuses() { + $statuses = array_keys( wc_gzd_get_shipment_statuses() ); + $statuses = array_diff( $statuses, array( 'gzd-draft', 'gzd-requested' ) ); + + return apply_filters( 'woocommerce_gzd_shipments_packaging_report_valid_statuses', $statuses ); + } + + /** + * @param $args + * + * @return \Vendidero\Germanized\Shipments\Shipment[] + */ + public static function query( $args ) { + $query_args = array( + 'date_created' => $args['start'] . '...' . $args['end'], + 'offset' => $args['offset'], + 'type' => $args['type'], + 'status' => $args['status'], + 'limit' => $args['limit'], + ); + + return wc_gzd_get_shipments( $query_args ); + } + + public static function cancel( $id ) { + $data = ReportHelper::get_report_data( $id ); + $generator = new AsyncReportGenerator( $data['type'], $data ); + $queue = self::get_queue(); + $running = self::get_reports_running(); + + if ( self::is_running( $id ) ) { + $running = array_diff( $running, array( $id ) ); + Package::log( sprintf( 'Cancelled %s', ReportHelper::get_report_title( $id ) ) ); + + update_option( 'woocommerce_gzd_shipments_packaging_reports_running', $running, false ); + self::clear_cache(); + $generator->delete(); + } + + /** + * Cancel outstanding events and queue new. + */ + $queue->cancel_all( self::get_hook_name( $id ) ); + } + + public static function get_queue() { + return function_exists( 'WC' ) ? WC()->queue() : false; + } + + public static function is_running( $id ) { + $running = self::get_reports_running(); + + if ( in_array( $id, $running, true ) && self::get_queue()->get_next( self::get_hook_name( $id ) ) ) { + return true; + } + + return false; + } + + public static function get_hook_name( $id ) { + if ( ! strstr( $id, 'woocommerce_gzd_shipments_' ) ) { + $id = 'woocommerce_gzd_shipments_' . $id; + } + + return $id; + } + + public static function next( $type, $args ) { + $generator = new AsyncReportGenerator( $type, $args ); + $result = $generator->next(); + $is_empty = false; + $queue = self::get_queue(); + + if ( is_wp_error( $result ) ) { + $is_empty = $result->get_error_message( 'empty' ); + } + + if ( ! $is_empty ) { + $new_args = $generator->get_args(); + + // Increase offset + $new_args['offset'] = (int) $new_args['offset'] + (int) $new_args['limit']; + + $queue->cancel_all( self::get_hook_name( $generator->get_id() ) ); + + Package::log( sprintf( 'Starting new queue: %s', wc_print_r( $new_args, true ) ) ); + + $queue->schedule_single( + time() + 10, + self::get_hook_name( $generator->get_id() ), + array( 'args' => $new_args ), + 'woocommerce_gzd_shipments' + ); + } else { + self::complete( $generator ); + } + } + + /** + * @param AsyncReportGenerator $generator + */ + public static function complete( $generator ) { + $queue = self::get_queue(); + $type = $generator->get_type(); + + /** + * Cancel outstanding events. + */ + $queue->cancel_all( self::get_hook_name( $generator->get_id() ) ); + + $report = $generator->complete(); + $status = 'failed'; + + if ( is_a( $report, '\Vendidero\Germanized\Shipments\Packaging\Report' ) && $report->exists() ) { + $status = 'completed'; + } + + Package::log( sprintf( 'Completed %1$s. Status: %2$s', $report->get_title(), $status ) ); + + self::maybe_stop_report( $report->get_id() ); + } + + public static function maybe_stop_report( $report_id ) { + $reports_running = self::get_reports_running(); + + if ( in_array( $report_id, $reports_running, true ) ) { + $reports_running = array_diff( $reports_running, array( $report_id ) ); + update_option( 'woocommerce_gzd_shipments_packaging_reports_running', $reports_running, false ); + + if ( $queue = self::get_queue() ) { + $queue->cancel_all( self::get_hook_name( $report_id ) ); + } + + /** + * Force non-cached running option + */ + wp_cache_delete( 'woocommerce_gzd_shipments_packaging_reports_running', 'options' ); + + return true; + } + + return false; + } + + public static function get_reports_running() { + return (array) get_option( 'woocommerce_gzd_shipments_packaging_reports_running', array() ); + } + + public static function get_timeframe( $type, $date = null, $date_end = null ) { + $date_start = null; + $date_end = is_null( $date_end ) ? null : $date_end; + $start_indicator = is_null( $date ) ? new \WC_DateTime() : $date; + + if ( ! is_a( $start_indicator, 'WC_DateTime' ) && is_numeric( $start_indicator ) ) { + $start_indicator = new \WC_DateTime( '@' . $start_indicator ); + } + + if ( ! is_null( $date_end ) && ! is_a( $date_end, 'WC_DateTime' ) && is_numeric( $date_end ) ) { + $date_end = new \WC_DateTime( '@' . $date_end ); + } + + if ( 'quarterly' === $type ) { + $month = $start_indicator->date( 'n' ); + $quarter = (int) ceil( $month / 3 ); + $start_month = 'Jan'; + $end_month = 'Mar'; + + if ( 2 === $quarter ) { + $start_month = 'Apr'; + $end_month = 'Jun'; + } elseif ( 3 === $quarter ) { + $start_month = 'Jul'; + $end_month = 'Sep'; + } elseif ( 4 === $quarter ) { + $start_month = 'Oct'; + $end_month = 'Dec'; + } + + $date_start = new \WC_DateTime( 'first day of ' . $start_month . ' ' . $start_indicator->format( 'Y' ) . ' midnight' ); + $date_end = new \WC_DateTime( 'last day of ' . $end_month . ' ' . $start_indicator->format( 'Y' ) . ' midnight' ); + } elseif ( 'monthly' === $type ) { + $month = $start_indicator->format( 'M' ); + + $date_start = new \WC_DateTime( 'first day of ' . $month . ' ' . $start_indicator->format( 'Y' ) . ' midnight' ); + $date_end = new \WC_DateTime( 'last day of ' . $month . ' ' . $start_indicator->format( 'Y' ) . ' midnight' ); + } elseif ( 'yearly' === $type ) { + $date_end = clone $start_indicator; + $date_start = clone $start_indicator; + + $date_end->modify( 'last day of dec ' . $start_indicator->format( 'Y' ) . ' midnight' ); + $date_start->modify( 'first day of jan ' . $start_indicator->format( 'Y' ) . ' midnight' ); + } else { + if ( is_null( $date_end ) ) { + $date_end = clone $start_indicator; + $date_end->modify( '-1 year' ); + } + + $date_start = clone $start_indicator; + } + + /** + * Always set start and end time to midnight + */ + if ( $date_start ) { + $date_start->setTime( 0, 0 ); + } + + if ( $date_end ) { + $date_end->setTime( 0, 0 ); + } + + return array( + 'start' => $date_start, + 'end' => $date_end, + ); + } +} diff --git a/packages/woocommerce-germanized-shipments/src/PackagingFactory.php b/packages/woocommerce-germanized-shipments/src/PackagingFactory.php new file mode 100644 index 000000000..4c48f8ec3 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/PackagingFactory.php @@ -0,0 +1,65 @@ +get_id(); + } elseif ( ! empty( $packaging->packaging_id ) ) { + return $packaging->packaging_id; + } else { + return false; + } + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Packing/Helper.php b/packages/woocommerce-germanized-shipments/src/Packing/Helper.php new file mode 100644 index 000000000..24c0abbb2 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Packing/Helper.php @@ -0,0 +1,31 @@ +get_id() ] = new PackagingBox( $packaging ); + } + } + + if ( $id ) { + return array_key_exists( $id, self::$packaging ) ? self::$packaging[ $id ] : false; + } + + return self::$packaging; + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Packing/OrderItem.php b/packages/woocommerce-germanized-shipments/src/Packing/OrderItem.php new file mode 100644 index 000000000..1dc130ee0 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Packing/OrderItem.php @@ -0,0 +1,117 @@ +item = $item; + + if ( ! is_callable( array( $item, 'get_product' ) ) ) { + throw new \Exception( 'Invalid item' ); + } + + if ( $product = $this->item->get_product() ) { + $this->product = $product; + + $width = empty( $this->product->get_width() ) ? 0 : wc_format_decimal( $this->product->get_width() ); + $length = empty( $this->product->get_length() ) ? 0 : wc_format_decimal( $this->product->get_length() ); + $depth = empty( $this->product->get_height() ) ? 0 : wc_format_decimal( $this->product->get_height() ); + + $this->dimensions = array( + 'width' => (int) wc_get_dimension( $width, 'mm' ), + 'length' => (int) wc_get_dimension( $length, 'mm' ), + 'depth' => (int) wc_get_dimension( $depth, 'mm' ), + ); + + $weight = empty( $this->product->get_weight() ) ? 0 : wc_format_decimal( $this->product->get_weight() ); + $this->weight = (int) wc_get_weight( $weight, 'g' ); + } + + if ( ! $product ) { + throw new \Exception( 'Missing product' ); + } + } + + public function get_id() { + return $this->item->get_id(); + } + + /** + * @return \WC_Order_Item_Product + */ + public function get_order_item() { + return $this->item; + } + + /** + * Item SKU etc. + */ + public function getDescription(): string { + if ( $this->product->get_sku() ) { + return $this->product->get_sku(); + } + + return $this->item->get_id(); + } + + /** + * Item width in mm. + */ + public function getWidth(): int { + return $this->dimensions['width']; + } + + /** + * Item length in mm. + */ + public function getLength(): int { + return $this->dimensions['length']; + } + + /** + * Item depth in mm. + */ + public function getDepth(): int { + return $this->dimensions['depth']; + } + + /** + * Item weight in g. + */ + public function getWeight(): int { + return $this->weight; + } + + /** + * Does this item need to be kept flat / packed "this way up"? + */ + public function getKeepFlat(): bool { + return false; + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Packing/PackagingBox.php b/packages/woocommerce-germanized-shipments/src/Packing/PackagingBox.php new file mode 100644 index 000000000..6abe9c7bb --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Packing/PackagingBox.php @@ -0,0 +1,147 @@ +packaging = $packaging; + + $width = empty( $this->packaging->get_width() ) ? 0 : wc_format_decimal( $this->packaging->get_width() ); + $length = empty( $this->packaging->get_length() ) ? 0 : wc_format_decimal( $this->packaging->get_length() ); + $depth = empty( $this->packaging->get_height() ) ? 0 : wc_format_decimal( $this->packaging->get_height() ); + + $this->dimensions = array( + 'width' => (int) floor( wc_get_dimension( $width, 'mm', wc_gzd_get_packaging_dimension_unit() ) ), + 'length' => (int) floor( wc_get_dimension( $length, 'mm', wc_gzd_get_packaging_dimension_unit() ) ), + 'depth' => (int) floor( wc_get_dimension( $depth, 'mm', wc_gzd_get_packaging_dimension_unit() ) ), + ); + + $weight = empty( $this->packaging->get_weight() ) ? 0 : wc_format_decimal( $this->packaging->get_weight() ); + $this->weight = (int) floor( wc_get_weight( $weight, 'g', wc_gzd_get_packaging_weight_unit() ) ); + + $max_content_weight = empty( $this->packaging->get_max_content_weight() ) ? 0 : wc_format_decimal( $this->packaging->get_max_content_weight() ); + $this->max_weight = (int) floor( wc_get_weight( $max_content_weight, 'g', wc_gzd_get_packaging_weight_unit() ) ); + + /** + * If no max weight was chosen - use 50kg as fallback + */ + if ( empty( $this->max_weight ) ) { + $this->max_weight = 50000; + } + } + + public function get_id() { + return $this->packaging->get_id(); + } + + /** + * Reference for box type (e.g. SKU or description). + */ + public function getReference(): string { + return (string) $this->packaging->get_title(); + } + + /** + * Outer width in mm. + */ + public function getOuterWidth(): int { + return $this->dimensions['width']; + } + + /** + * Outer length in mm. + */ + public function getOuterLength(): int { + return $this->dimensions['length']; + } + + /** + * Outer depth in mm. + */ + public function getOuterDepth(): int { + return $this->dimensions['depth']; + } + + /** + * Empty weight in g. + */ + public function getEmptyWeight(): int { + return $this->weight; + } + + /** + * Returns the threshold by which the inner dimension gets reduced + * in comparison to the outer dimension. + * + * @param string $type + * + * @return float + */ + public function get_inner_dimension_buffer( $value, $type = 'width' ) { + if ( apply_filters( 'woocommerce_gzd_packaging_inner_dimension_use_percentage_buffer', false, $type, $this ) ) { + $percentage_buffer = apply_filters( 'woocommerce_gzd_packaging_inner_dimension_percentage_buffer', 0.5, $type, $this ) / 100; + $value = $value - ( $value * $percentage_buffer ); + } else { + $fixed_buffer = apply_filters( 'woocommerce_gzd_packaging_inner_dimension_fixed_buffer_mm', 5, $type, $this ); + $value = $value - $fixed_buffer; + } + + return max( $value, 0 ); + } + + /** + * Inner width in mm. + */ + public function getInnerWidth(): int { + $width = $this->get_inner_dimension_buffer( $this->dimensions['width'], 'width' ); + + return $width; + } + + /** + * Inner length in mm. + */ + public function getInnerLength(): int { + $length = $this->get_inner_dimension_buffer( $this->dimensions['length'], 'length' ); + + return $length; + } + + /** + * Inner depth in mm. + */ + public function getInnerDepth(): int { + $depth = $this->get_inner_dimension_buffer( $this->dimensions['depth'], 'depth' ); + + return $depth; + } + + /** + * Max weight the packaging can hold in g. + */ + public function getMaxWeight(): int { + return $this->max_weight; + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Packing/ShipmentItem.php b/packages/woocommerce-germanized-shipments/src/Packing/ShipmentItem.php new file mode 100644 index 000000000..e4a347676 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Packing/ShipmentItem.php @@ -0,0 +1,111 @@ +item = $item; + + if ( $shipment = $item->get_shipment() ) { + $dimension_unit = $shipment->get_dimension_unit(); + $weight_unit = $shipment->get_weight_unit(); + } else { + $dimension_unit = get_option( 'woocommerce_dimension_unit', 'cm' ); + $weight_unit = get_option( 'woocommerce_weight_unit', 'kg' ); + } + + $width = empty( $this->item->get_width() ) ? 0 : wc_format_decimal( $this->item->get_width() ); + $length = empty( $this->item->get_length() ) ? 0 : wc_format_decimal( $this->item->get_length() ); + $depth = empty( $this->item->get_height() ) ? 0 : wc_format_decimal( $this->item->get_height() ); + + $this->dimensions = array( + 'width' => (int) ceil( wc_get_dimension( $width, 'mm', $dimension_unit ) ), + 'length' => (int) ceil( wc_get_dimension( $length, 'mm', $dimension_unit ) ), + 'depth' => (int) ceil( wc_get_dimension( $depth, 'mm', $dimension_unit ) ), + ); + + $weight = empty( $this->item->get_weight() ) ? 0 : wc_format_decimal( $this->item->get_weight() ); + $this->weight = (int) ceil( wc_get_weight( $weight, 'g', $weight_unit ) ); + } + + /** + * @return \Vendidero\Germanized\Shipments\ShipmentItem + */ + public function get_shipment_item() { + return $this->item; + } + + public function get_id() { + return $this->item->get_id(); + } + + /** + * Item SKU etc. + */ + public function getDescription(): string { + if ( $this->item->get_sku() ) { + return $this->item->get_sku(); + } + + return $this->item->get_id(); + } + + /** + * Item width in mm. + */ + public function getWidth(): int { + return $this->dimensions['width']; + } + + /** + * Item length in mm. + */ + public function getLength(): int { + return $this->dimensions['length']; + } + + /** + * Item depth in mm. + */ + public function getDepth(): int { + return $this->dimensions['depth']; + } + + /** + * Item weight in g. + */ + public function getWeight(): int { + return $this->weight; + } + + /** + * Does this item need to be kept flat / packed "this way up"? + */ + public function getKeepFlat(): bool { + return false; + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Product.php b/packages/woocommerce-germanized-shipments/src/Product.php new file mode 100644 index 000000000..d1e739d1c --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Product.php @@ -0,0 +1,130 @@ +product = $product; + } + + /** + * Returns the Woo WC_Product original object + * + * @return object|WC_Product + */ + public function get_product() { + return $this->product; + } + + protected function get_forced_parent_product() { + if ( $this->product->is_type( 'variation' ) ) { + if ( $parent = wc_get_product( $this->product->get_parent_id() ) ) { + return $parent; + } + } + + return $this->product; + } + + public function get_hs_code( $context = 'view' ) { + $legacy_data = $this->get_forced_parent_product()->get_meta( '_dhl_hs_code', true, $context ); + $data = $this->get_forced_parent_product()->get_meta( '_hs_code', true, $context ); + + if ( '' === $data && ! empty( $legacy_data ) ) { + $data = $legacy_data; + } + + return $data; + } + + public function get_manufacture_country( $context = 'view' ) { + $legacy_data = $this->get_forced_parent_product()->get_meta( '_dhl_manufacture_country', true, $context ); + $data = $this->get_forced_parent_product()->get_meta( '_manufacture_country', true, $context ); + + if ( '' === $data && ! empty( $legacy_data ) ) { + $data = $legacy_data; + } + + if ( '' === $data && 'view' === $context ) { + return wc_get_base_location()['country']; + } + + return $data; + } + + public function get_main_category() { + $ids = $this->get_forced_parent_product()->get_category_ids(); + $term_name = ''; + + if ( ! empty( $ids ) ) { + foreach ( $ids as $term_id ) { + $term = get_term( $term_id, 'product_cat' ); + + if ( empty( $term->slug ) ) { + continue; + } + + $term_name = $term->name; + break; + } + } + + return $term_name; + } + + public function set_hs_code( $code ) { + $this->product->update_meta_data( '_hs_code', $code ); + } + + public function set_manufacture_country( $country ) { + $this->product->update_meta_data( '_manufacture_country', substr( wc_strtoupper( $country ), 0, 2 ) ); + } + + /** + * Call child methods if the method does not exist. + * + * @param $method + * @param $args + * + * @return bool|mixed + */ + public function __call( $method, $args ) { + if ( method_exists( $this->product, $method ) ) { + return call_user_func_array( array( $this->product, $method ), $args ); + } + + return false; + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Rest/ShipmentsController.php b/packages/woocommerce-germanized-shipments/src/Rest/ShipmentsController.php new file mode 100644 index 000000000..605d580d5 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Rest/ShipmentsController.php @@ -0,0 +1,2053 @@ +namespace, + '/' . $this->rest_base, + array( + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_items' ), + 'permission_callback' => array( $this, 'get_items_permissions_check' ), + 'args' => $this->get_collection_params(), + ), + array( + 'methods' => WP_REST_Server::CREATABLE, + 'callback' => array( $this, 'create_item' ), + 'permission_callback' => array( $this, 'create_item_permissions_check' ), + 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), + ), + 'schema' => array( $this, 'get_public_item_schema' ), + ) + ); + register_rest_route( + $this->namespace, + '/' . $this->rest_base . '/(?P[\d]+)', + array( + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_item' ), + 'permission_callback' => array( $this, 'get_item_permissions_check' ), + 'args' => array( + 'context' => $this->get_context_param( array( 'default' => 'view' ) ), + ), + ), + array( + 'methods' => WP_REST_Server::EDITABLE, + 'callback' => array( $this, 'update_item' ), + 'permission_callback' => array( $this, 'update_item_permissions_check' ), + 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), + ), + array( + 'methods' => WP_REST_Server::DELETABLE, + 'callback' => array( $this, 'delete_item' ), + 'permission_callback' => array( $this, 'delete_item_permissions_check' ), + 'args' => array( + 'force' => array( + 'default' => false, + 'type' => 'boolean', + 'description' => _x( 'Whether to bypass trash and force deletion.', 'shipments', 'woocommerce-germanized' ), + ), + ), + ), + 'schema' => array( $this, 'get_public_item_schema' ), + ) + ); + + register_rest_route( + $this->namespace, + '/' . $this->rest_base . '/(?P[\d]+)/label', + array( + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_label' ), + 'permission_callback' => array( $this, 'get_label_permissions_check' ), + 'args' => array( + 'context' => $this->get_context_param( array( 'default' => 'view' ) ), + ), + ), + array( + 'methods' => WP_REST_Server::CREATABLE, + 'callback' => array( $this, 'create_label' ), + 'permission_callback' => array( $this, 'create_label_permissions_check' ), + 'args' => array( + array( + 'description' => _x( 'Shipment label.', 'shipment', 'woocommerce-germanized' ), + 'context' => array( 'view', 'edit' ), + 'readonly' => false, + 'type' => 'object', + 'properties' => array( + 'type' => 'object', + 'properties' => array( + 'key' => array( + 'description' => _x( 'Label field key.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'value' => array( + 'description' => _x( 'Label field value.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'mixed', + 'context' => array( 'view', 'edit' ), + ), + ), + ), + ), + ), + ), + array( + 'methods' => WP_REST_Server::DELETABLE, + 'callback' => array( $this, 'delete_label' ), + 'permission_callback' => array( $this, 'delete_label_permissions_check' ), + 'args' => array( + 'force' => array( + 'default' => false, + 'type' => 'boolean', + 'description' => _x( 'Whether to bypass trash and force deletion.', 'shipments', 'woocommerce-germanized' ), + ), + ), + ), + 'schema' => array( $this, 'get_public_item_label_schema' ), + ) + ); + } + + /** + * Get object. + * + * @param int|Shipment $id Object ID. + * @return Shipment Shipment object or WP_Error object. + */ + protected function get_object( $id ) { + return $this->get_shipment( $id ); + } + + /** + * Get object permalink. + * + * @param Shipment $shipment Object. + * @return string + */ + protected function get_permalink( $shipment ) { + return $shipment->get_edit_shipment_url(); + } + + private static function get_shipment_statuses() { + return array_map( array( 'Vendidero\Germanized\Shipments\Api', 'remove_status_prefix' ), array_keys( wc_gzd_get_shipment_statuses() ) ); + } + + /** + * Checks if a given request has access to get a specific item. + * + * @param WP_REST_Request $request Full details about the request. + * + * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. + * @since 4.7.0 + */ + public function get_item_permissions_check( $request ) { + if ( ! $this->check_permissions( 'shipment', 'read', $request['id'] ) ) { + return new WP_Error( 'woocommerce_gzd_rest_cannot_view', _x( 'Sorry, you are not allowed to view this resource.', 'shipments', 'woocommerce-germanized' ), array( 'status' => rest_authorization_required_code() ) ); + } + + return true; + } + + /** + * Retrieves a shipment by id. + * + * @param int $shipment_id + * + * @return Shipment|false + */ + private function get_shipment( $shipment_id ) { + $shipment = wc_gzd_get_shipment( $shipment_id ); + + return $shipment; + } + + /** + * Checks if a given request has access to get a specific item. + * + * @param WP_REST_Request $request Full details about the request. + * + * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. + * @since 4.7.0 + */ + public function get_items_permissions_check( $request ) { + if ( ! $this->check_permissions() ) { + return new WP_Error( 'woocommerce_gzd_rest_cannot_view', _x( 'Sorry, you cannot list resources.', 'shipments', 'woocommerce-germanized' ), array( 'status' => rest_authorization_required_code() ) ); + } + + return true; + } + + protected function check_permissions( $object_type = 'shipment', $context = 'read', $object_id = 0 ) { + if ( 'delete' === $context || 'edit' === $context ) { + $post_type_object = get_post_type_object( 'shop_order' ); + $capped = 'delete' === $context ? $post_type_object->cap->delete_posts : $post_type_object->cap->edit_posts; + $permission = current_user_can( $capped, $object_id ); + } else { + $permission = wc_rest_check_post_permissions( 'shop_order', $context ); + } + + return apply_filters( 'woocommerce_gzd_shipments_rest_check_permissions', $permission, $object_type, $context, $object_id ); + } + + /** + * Retrieves a collection of items. + * + * @param WP_REST_Request $request Full details about the request. + * + * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. + * @since 4.7.0 + */ + public function get_items( $request ) { + $prepared_args = array( + 'limit' => $request['per_page'], + 'paginate' => true, + 'type' => $request['type'], + 'order_id' => $request['order_id'], + 'search' => $request['search'], + 'status' => $request['status'], + 'order' => $request['order'], + 'orderby' => $request['orderby'], + 'count_total' => true, + ); + + if ( ! empty( $prepared_args['search'] ) ) { + $prepared_args['search'] = '*' . $prepared_args['search'] . '*'; + } + + if ( ! empty( $request['offset'] ) ) { + $prepared_args['offset'] = $request['offset']; + } else { + $prepared_args['offset'] = ( $request['page'] - 1 ) * $prepared_args['limit']; + } + + $objects = array(); + $query = new \Vendidero\Germanized\Shipments\ShipmentQuery( $prepared_args ); + $shipments = $query->get_shipments(); + + if ( ! empty( $shipments ) ) { + foreach ( $shipments as $shipment ) { + if ( ! $this->check_permissions( 'shipment', 'read', $shipment->get_id() ) ) { + continue; + } + + $objects[] = $this->prepare_object_for_response( $shipment, $request ); + } + } + + $page = (int) $request['page']; + $max_pages = $query->get_max_num_pages(); + + $response = rest_ensure_response( $objects ); + $response->header( 'X-WP-Total', $query->get_total() ); + $response->header( 'X-WP-TotalPages', (int) $max_pages ); + + $base = $this->rest_base; + $attrib_prefix = '(?P<'; + if ( strpos( $base, $attrib_prefix ) !== false ) { + $attrib_names = array(); + preg_match( '/\(\?P<[^>]+>.*\)/', $base, $attrib_names, PREG_OFFSET_CAPTURE ); + foreach ( $attrib_names as $attrib_name_match ) { + $beginning_offset = strlen( $attrib_prefix ); + $attrib_name_end = strpos( $attrib_name_match[0], '>', $attrib_name_match[1] ); + $attrib_name = substr( $attrib_name_match[0], $beginning_offset, $attrib_name_end - $beginning_offset ); + if ( isset( $request[ $attrib_name ] ) ) { + $base = str_replace( "(?P<$attrib_name>[\d]+)", $request[ $attrib_name ], $base ); + } + } + } + $base = add_query_arg( $request->get_query_params(), rest_url( sprintf( '/%s/%s', $this->namespace, $base ) ) ); + + if ( $page > 1 ) { + $prev_page = $page - 1; + if ( $prev_page > $max_pages ) { + $prev_page = $max_pages; + } + $prev_link = add_query_arg( 'page', $prev_page, $base ); + $response->link_header( 'prev', $prev_link ); + } + if ( $max_pages > $page ) { + $next_page = $page + 1; + $next_link = add_query_arg( 'page', $next_page, $base ); + $response->link_header( 'next', $next_link ); + } + + return $response; + } + + /** + * Checks if a given request has access to update a specific item. + * + * @param WP_REST_Request $request Full details about the request. + * + * @return true|WP_Error True if the request has access to update the item, WP_Error object otherwise. + * @since 4.7.0 + */ + public function update_item_permissions_check( $request ) { + if ( ! $this->check_permissions( 'shipment', 'edit', $request['id'] ) ) { + return new WP_Error( 'woocommerce_gzd_rest_cannot_edit', _x( 'Sorry, you are not allowed to edit this resource.', 'shipments', 'woocommerce-germanized' ), array( 'status' => rest_authorization_required_code() ) ); + } + + return true; + } + + /** + * Checks if a given request has access to create a specific item. + * + * @param WP_REST_Request $request Full details about the request. + * + * @return true|WP_Error True if the request has access to create the item, WP_Error object otherwise. + * @since 4.7.0 + */ + public function create_item_permissions_check( $request ) { + if ( ! $this->check_permissions( 'shipment', 'create' ) ) { + return new WP_Error( 'woocommerce_gzd_rest_cannot_view', _x( 'Sorry, you are not allowed to create resources.', 'shipments', 'woocommerce-germanized' ), array( 'status' => rest_authorization_required_code() ) ); + } + + return true; + } + + /** + * @param $request + * @param boolean $creating + * + * @return Shipment + * @throws \WC_REST_Exception + */ + protected function prepare_object_for_database( $request, $creating = false ) { + $id = isset( $request['id'] ) ? absint( $request['id'] ) : false; + + // Type is the most important part here because we need to be using the correct class and methods. + if ( isset( $request['type'] ) ) { + $shipment = ShipmentFactory::get_shipment( $id, $request['type'] ); + } elseif ( $id ) { + $shipment = wc_gzd_get_shipment( $id ); + } else { + $shipment = ShipmentFactory::get_shipment( false ); + } + + if ( ! $shipment ) { + throw new \WC_REST_Exception( 'woocommerce_gzd_rest_invalid_id', _x( 'There was an error while creating the shipment.', 'shipments', 'woocommerce-germanized' ) ); + } + + if ( isset( $request['order_id'] ) ) { + $shipment->set_order_id( absint( wp_unslash( $request['order_id'] ) ) ); + } + + if ( $creating ) { + $order_shipment = $shipment->get_order_shipment(); + + if ( ! $order_shipment ) { + throw new \WC_REST_Exception( 'woocommerce_gzd_rest_invalid_id', _x( 'This order does not exist.', 'shipments', 'woocommerce-germanized' ) ); + } + + if ( 'return' === $shipment->get_type() ) { + if ( ! $order_shipment->needs_return() ) { + throw new \WC_REST_Exception( 'woocommerce_gzd_rest_invalid_id', _x( 'This order does need a return.', 'shipments', 'woocommerce-germanized' ) ); + } + } else { + if ( ! $order_shipment->needs_shipping() ) { + throw new \WC_REST_Exception( 'woocommerce_gzd_rest_invalid_id', _x( 'This order does need shipping.', 'shipments', 'woocommerce-germanized' ) ); + } + } + + $shipment->sync(); + } + + if ( isset( $request['shipping_provider'] ) ) { + $provider = wc_clean( wp_unslash( $request['shipping_provider'] ) ); + + if ( $provider = wc_gzd_get_shipping_provider( $provider ) ) { + $shipment->set_shipping_provider( $provider ); + } + } + + if ( isset( $request['shipping_method'] ) ) { + $shipment->set_shipping_method( wc_clean( wp_unslash( $request['shipping_method'] ) ) ); + } + + if ( isset( $request['packaging_id'] ) ) { + $packaging_id = absint( wp_unslash( $request['packaging_id'] ) ); + + if ( $packaging = wc_gzd_get_packaging( $packaging_id ) ) { + $shipment->set_packaging_id( $packaging_id ); + } + } + + if ( isset( $request['packaging_weight'] ) ) { + $shipment->set_packaging_weight( wc_clean( wp_unslash( $request['packaging_weight'] ) ) ); + } + + if ( isset( $request['tracking_id'] ) ) { + $shipment->set_tracking_id( wc_clean( wp_unslash( $request['tracking_id'] ) ) ); + } + + if ( isset( $request['dimensions'] ) ) { + if ( isset( $request['dimensions']['length'] ) ) { + $shipment->set_length( wc_clean( wp_unslash( $request['dimensions']['length'] ) ) ); + } + if ( isset( $request['dimensions']['width'] ) ) { + $shipment->set_width( wc_clean( wp_unslash( $request['dimensions']['width'] ) ) ); + } + if ( isset( $request['dimensions']['height'] ) ) { + $shipment->set_height( wc_clean( wp_unslash( $request['dimensions']['height'] ) ) ); + } + } + + if ( isset( $request['dimension_unit'] ) ) { + $shipment->set_dimension_unit( wc_clean( wp_unslash( $request['dimension_unit'] ) ) ); + } + + if ( isset( $request['weight'] ) ) { + $shipment->set_weight( wc_clean( wp_unslash( $request['weight'] ) ) ); + } + + if ( isset( $request['weight_unit'] ) ) { + $shipment->set_weight_unit( wc_clean( wp_unslash( $request['weight_unit'] ) ) ); + } + + if ( isset( $request['address'] ) && is_array( $request['address'] ) ) { + $shipment->set_address( wc_clean( wp_unslash( $request['address'] ) ) ); + + if ( isset( $request['address']['country'] ) ) { + $shipment->set_country( wc_clean( wp_unslash( $request['address']['country'] ) ) ); + } + } + + if ( isset( $request['total'] ) ) { + $shipment->set_total( wc_clean( wp_unslash( $request['total'] ) ) ); + } + + if ( isset( $request['subtotal'] ) ) { + $shipment->set_subtotal( wc_clean( wp_unslash( $request['subtotal'] ) ) ); + } + + if ( isset( $request['additional_total'] ) ) { + $shipment->set_additional_total( wc_clean( wp_unslash( $request['additional_total'] ) ) ); + } + + if ( is_a( $shipment, 'Vendidero\Germanized\Shipments\ReturnShipment' ) ) { + if ( isset( $request['sender_address'] ) && is_array( $request['sender_address'] ) ) { + $shipment->set_sender_address( wc_clean( wp_unslash( $request['sender_address'] ) ) ); + } + + if ( isset( $request['is_customer_requested'] ) ) { + $shipment->set_is_customer_requested( wc_clean( wp_unslash( $request['is_customer_requested'] ) ) ); + } + } + + if ( ! empty( $request['date_created'] ) ) { + $date = rest_parse_date( wc_clean( wp_unslash( $request['date_created'] ) ) ); + + if ( $date ) { + $shipment->set_date_created( $date ); + } + } + + if ( ! empty( $request['date_created_gmt'] ) ) { + $date = rest_parse_date( wc_clean( wp_unslash( $request['date_created_gmt'] ) ), true ); + + if ( $date ) { + $shipment->set_date_created( $date ); + } + } + + if ( ! empty( $request['est_delivery_date'] ) ) { + $date = rest_parse_date( wc_clean( wp_unslash( $request['est_delivery_date'] ) ) ); + + if ( $date ) { + $shipment->set_est_delivery_date( $date ); + } + } + + if ( ! empty( $request['est_delivery_date_gmt'] ) ) { + $date = rest_parse_date( wc_clean( wp_unslash( $request['est_delivery_date_gmt'] ) ), true ); + + if ( $date ) { + $shipment->set_est_delivery_date( $date ); + } + } + + if ( ! empty( $request['date_sent'] ) ) { + $date = rest_parse_date( wc_clean( wp_unslash( $request['date_sent'] ) ) ); + + if ( $date ) { + $shipment->set_date_sent( $date ); + } + } + + if ( ! empty( $request['date_sent_gmt'] ) ) { + $date = rest_parse_date( wc_clean( wp_unslash( $request['date_sent_gmt'] ) ), true ); + + if ( $date ) { + $shipment->set_date_sent( $date ); + } + } + + if ( ! empty( $request['items'] ) && is_array( $request['items'] ) ) { + foreach ( $request['items'] as $item ) { + if ( is_array( $item ) ) { + if ( $this->item_is_null( $item ) || ( isset( $item['quantity'] ) && 0 === $item['quantity'] ) ) { + $shipment->remove_item( $item['id'] ); + } else { + $this->set_item( $shipment, $item ); + } + } + } + } elseif ( $creating ) { + $shipment->sync_items(); + } + + // Update the status at last + if ( isset( $request['status'] ) ) { + $status = str_replace( 'gzd-', '', wc_clean( wp_unslash( $request['status'] ) ) ); + + if ( in_array( $status, self::get_shipment_statuses(), true ) ) { + $shipment->set_status( $status ); + } + } + + if ( isset( $request['meta_data'] ) && is_array( $request['meta_data'] ) ) { + foreach ( $request['meta_data'] as $meta ) { + $meta = wc_clean( wp_unslash( $meta ) ); + + if ( isset( $meta['key'] ) ) { + $value = isset( $meta['value'] ) ? $meta['value'] : null; + $shipment->update_meta_data( $meta['key'], $value, isset( $meta['id'] ) ? $meta['id'] : '' ); + } + } + } + + if ( $shipment->get_item_count() <= 0 ) { + $shipment->delete( true ); + + throw new \WC_REST_Exception( 'woocommerce_gzd_rest_invalid_id', _x( 'This shipment does not contain any items and was deleted.', 'shipments', 'woocommerce-germanized' ) ); + } + + /** + * Filters a shipment before it is inserted via the REST API. + * + * @param Shipment $shipment Shipment object. + * @param WP_REST_Request $request Request object. + */ + return apply_filters( 'woocommerce_gzd_rest_pre_insert_shipment_object', $shipment, $request ); + } + + /** + * Wrapper method to create/update order items. + * When updating, the item ID provided is checked to ensure it is associated + * with the order. + * + * @param Shipment $shipment order object. + * @param array $posted item provided in the request body. + * + * @throws \WC_REST_Exception If item ID is not associated with order. + */ + protected function set_item( $shipment, $posted ) { + if ( ! empty( $posted['id'] ) ) { + $action = 'update'; + } else { + $action = 'create'; + } + + $item = null; + + // Verify provided line item ID is associated with order. + if ( 'update' === $action ) { + $item = $shipment->get_item( absint( $posted['id'] ) ); + + if ( ! $item ) { + throw new \WC_REST_Exception( 'woocommerce_gzd_rest_invalid_item_id', _x( 'Shipment item ID provided is not associated with shipment.', 'shipments', 'woocommerce-germanized' ), 400 ); + } + } + + if ( is_null( $item ) ) { + if ( 'return' === $shipment->get_type() ) { + $item = new \Vendidero\Germanized\Shipments\ShipmentReturnItem(); + } else { + $item = new \Vendidero\Germanized\Shipments\ShipmentItem(); + } + } + + if ( isset( $posted['order_item_id'] ) ) { + $item->set_order_item_id( absint( wp_unslash( $posted['order_item_id'] ) ) ); + } + + $item->set_shipment( $shipment ); + + /** + * Sync quantity first. + */ + if ( 'create' === $action ) { + $quantity = isset( $posted['quantity'] ) ? absint( wp_unslash( $posted['quantity'] ) ) : -1; + $quantity_left = 0; + + if ( $order_shipment = $shipment->get_order_shipment() ) { + if ( 'return' === $shipment->get_type() ) { + $quantity_left = $order_shipment->get_item_quantity_left_for_returning( $item->get_order_item_id() ); + } elseif ( $order_item = $item->get_order_item() ) { + $quantity_left = $order_shipment->get_item_quantity_left_for_shipping( $order_item ); + } + + if ( -1 !== $quantity ) { + if ( $quantity > $quantity_left ) { + $quantity = $quantity_left; + } + } else { + $quantity = $quantity_left; + } + } + + if ( $quantity <= 0 ) { + throw new \WC_REST_Exception( 'woocommerce_gzd_rest_invalid_item_id', _x( 'This order item does not need shipping/returning.', 'shipments', 'woocommerce-germanized' ), 400 ); + } + + if ( $shipment->get_item_by_order_item_id( $item->get_order_item_id() ) ) { + throw new \WC_REST_Exception( 'woocommerce_gzd_rest_invalid_item_id', _x( 'The order item is already associated with another item.', 'shipments', 'woocommerce-germanized' ), 400 ); + } + + $item->sync( array( 'quantity' => $quantity ) ); + } else { + if ( $order_shipment = $shipment->get_order_shipment() ) { + $quantity = isset( $posted['quantity'] ) ? absint( wp_unslash( $posted['quantity'] ) ) : $item->get_quantity(); + $quantity_left = 0; + + if ( 'return' === $shipment->get_type() ) { + $quantity_left = $order_shipment->get_item_quantity_left_for_returning( + $item->get_order_item_id(), + array( + 'exclude_current_shipment' => true, + 'shipment_id' => $shipment->get_id(), + ) + ); + } elseif ( $order_item = $item->get_order_item() ) { + $quantity_left = $order_shipment->get_item_quantity_left_for_shipping( + $order_item, + array( + 'exclude_current_shipment' => true, + 'shipment_id' => $shipment->get_id(), + ) + ); + } + + if ( $quantity > $quantity_left ) { + $quantity = $quantity_left; + } + + if ( $quantity <= 0 ) { + $shipment->remove_item( $item->get_id() ); + return; + } + + $shipment->update_item_quantity( $item->get_id(), $quantity ); + } + } + + $props_to_set = array( + 'name', + 'product_id', + 'sku', + 'total', + 'subtotal', + 'weight', + 'hs_code', + 'manufacture_country', + 'return_reason_code', + ); + + foreach ( $props_to_set as $prop ) { + $setter = "set_{$prop}"; + + if ( isset( $posted[ $prop ] ) && is_callable( array( $item, $setter ) ) ) { + $item->{$setter}( wc_clean( wp_unslash( $posted[ $prop ] ) ) ); + } + } + + if ( isset( $posted['dimensions'] ) && is_array( $posted['dimensions'] ) ) { + if ( isset( $posted['dimensions']['length'] ) ) { + $item->set_length( wc_clean( wp_unslash( $posted['dimensions']['length'] ) ) ); + } + if ( isset( $posted['dimensions']['width'] ) ) { + $item->set_width( wc_clean( wp_unslash( $posted['dimensions']['width'] ) ) ); + } + if ( isset( $posted['dimensions']['height'] ) ) { + $item->set_height( wc_clean( wp_unslash( $posted['dimensions']['height'] ) ) ); + } + } + + if ( isset( $posted['attributes'] ) && is_array( $posted['attributes'] ) ) { + $attributes_to_save = array(); + + foreach ( $posted['attributes'] as $attribute ) { + $attribute = wc_clean( wp_unslash( $attribute ) ); + $attribute = wp_parse_args( + $attribute, + array( + 'key' => '', + 'value' => '', + 'label' => '', + 'order_item_meta_id' => 0, + ) + ); + + $attributes_to_save[] = array_intersect_key( $attribute, array_flip( array( 'key', 'value', 'label', 'order_item_meta_id' ) ) ); + } + + $item->set_attributes( $attributes_to_save ); + } + + if ( ! empty( $posted['meta_data'] ) && is_array( $posted['meta_data'] ) ) { + foreach ( $posted['meta_data'] as $meta ) { + $meta = wc_clean( wp_unslash( $meta ) ); + + if ( isset( $meta['key'] ) ) { + $value = isset( $meta['value'] ) ? $meta['value'] : null; + $item->update_meta_data( $meta['key'], $value, isset( $meta['id'] ) ? $meta['id'] : '' ); + } + } + } + + do_action( 'woocommerce_gzd_rest_set_shipment_item', $item, $posted ); + + // If creating the shipment, add the item to it. + if ( 'create' === $action ) { + $shipment->add_item( $item ); + } else { + $item->save(); + } + } + + /** + * Helper method to check if the resource ID associated with the provided item is null. + * Items can be deleted by setting the resource ID to null. + * + * @param array $item Item provided in the request body. + * @return bool True if the item resource ID is null, false otherwise. + */ + protected function item_is_null( $item ) { + $keys = array( 'order_item_id', 'name', 'product_id' ); + + foreach ( $keys as $key ) { + if ( array_key_exists( $key, $item ) && is_null( $item[ $key ] ) ) { + return true; + } + } + + return false; + } + + /** + * Save an object data. + * + * @since 3.0.0 + * @param WP_REST_Request $request Full details about the request. + * @param bool $creating If is creating a new object. + * @return Shipment|WP_Error + */ + protected function save_object( $request, $creating = false ) { + try { + $object = $this->prepare_object_for_database( $request, $creating ); + + if ( is_wp_error( $object ) ) { + return $object; + } + + $object->save(); + + return $this->get_object( $object->get_id() ); + } catch ( \WC_Data_Exception $e ) { + return new WP_Error( $e->getErrorCode(), $e->getMessage(), $e->getErrorData() ); + } catch ( \WC_REST_Exception $e ) { + return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); + } + } + + /** + * Create a single item. + * + * @param WP_REST_Request $request Full details about the request. + * @return WP_Error|WP_REST_Response + */ + public function create_item( $request ) { + if ( ! empty( $request['id'] ) ) { + /* translators: %s: post type */ + return new WP_Error( 'woocommerce_gzd_rest_shipment_exists', _x( 'Cannot create existing shipment.', 'shipments', 'woocommerce-germanized' ), array( 'status' => 400 ) ); + } + + $object = $this->save_object( $request, true ); + + if ( is_wp_error( $object ) ) { + return $object; + } + + try { + $this->update_additional_fields_for_object( $object, $request ); + + /** + * Fires after a single object is created or updated via the REST API. + * + * @param Shipment $shipment Inserted object. + * @param WP_REST_Request $request Request object. + * @param boolean $creating True when creating object, false when updating. + */ + do_action( 'woocommerce_gzd_rest_insert_shipment_object', $object, $request, true ); + } catch ( \WC_Data_Exception $e ) { + $object->delete(); + return new WP_Error( $e->getErrorCode(), $e->getMessage(), $e->getErrorData() ); + } catch ( \WC_REST_Exception $e ) { + $object->delete(); + return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); + } + + $request->set_param( 'context', 'edit' ); + $response = $this->prepare_object_for_response( $object, $request ); + $response = rest_ensure_response( $response ); + $response->set_status( 201 ); + $response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $object->get_id() ) ) ); + + return $response; + } + + /** + * Update a single post. + * + * @param WP_REST_Request $request Full details about the request. + * @return WP_Error|WP_REST_Response + */ + public function update_item( $request ) { + $shipment = $this->get_object( (int) $request['id'] ); + + if ( ! $shipment || 0 === $shipment->get_id() ) { + return new WP_Error( 'woocommerce_gzd_rest_shipment_invalid_id', _x( 'Invalid ID.', 'shipments', 'woocommerce-germanized' ), array( 'status' => 400 ) ); + } + + $shipment = $this->save_object( $request, false ); + + if ( is_wp_error( $shipment ) ) { + return $shipment; + } + + try { + $this->update_additional_fields_for_object( $shipment, $request ); + + /** + * Fires after a single shipment is created or updated via the REST API. + * + * @param Shipment $shipment Inserted object. + * @param WP_REST_Request $request Request object. + * @param boolean $creating True when creating object, false when updating. + */ + do_action( 'woocommerce_gzd_rest_insert_shipment_object', $shipment, $request, false ); + } catch ( \WC_Data_Exception $e ) { + return new WP_Error( $e->getErrorCode(), $e->getMessage(), $e->getErrorData() ); + } catch ( \WC_REST_Exception $e ) { + return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); + } + + $request->set_param( 'context', 'edit' ); + $response = $this->prepare_object_for_response( $shipment, $request ); + + return rest_ensure_response( $response ); + } + + /** + * Prepares the object for the REST response. + * + * @since 3.0.0 + * @param Shipment $shipment Object data. + * @param WP_REST_Request $request Request object. + * @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure. + */ + protected function prepare_object_for_response( $shipment, $request ) { + $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; + $this->request = $request; + $data = self::prepare_shipment( $shipment, $context ); + $data = $this->add_additional_fields_to_object( $data, $request ); + $data = $this->filter_response_by_context( $data, $context ); + $response = rest_ensure_response( $data ); + + $response->add_links( $this->prepare_links( $shipment, $request ) ); + + /** + * Filter the shipment data for a response. + * + * @param WP_REST_Response $response The response object. + * @param Shipment $shipment Object data. + * @param WP_REST_Request $request Request object. + */ + return apply_filters( 'woocommerce_gzd_rest_prepare_shipment_object', $response, $shipment, $request ); + } + + /** + * Prepare links for the request. + * + * @param Shipment $shipment Object data. + * @param WP_REST_Request $request Request object. + * @return array Links for the given post. + */ + protected function prepare_links( $shipment, $request ) { + $links = array( + 'self' => array( + 'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $shipment->get_id() ) ), + ), + 'collection' => array( + 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ), + ), + ); + + return $links; + } + + /** + * Get a single item. + * + * @param WP_REST_Request $request Full details about the request. + * @return WP_Error|WP_REST_Response + */ + public function get_item( $request ) { + $object = $this->get_object( (int) $request['id'] ); + + if ( ! $object || 0 === $object->get_id() ) { + return new WP_Error( 'woocommerce_gzd_rest_shipment_invalid_id', _x( 'Invalid ID.', 'shipments', 'woocommerce-germanized' ), array( 'status' => 404 ) ); + } + + $data = $this->prepare_object_for_response( $object, $request ); + $response = rest_ensure_response( $data ); + + return $response; + } + + /** + * Checks if a given request has access to delete a specific item. + * + * @param WP_REST_Request $request Full details about the request. + * + * @return true|WP_Error True if the request has access to delete the item, WP_Error object otherwise. + * @since 4.7.0 + */ + public function delete_item_permissions_check( $request ) { + if ( ! $this->check_permissions( 'shipment', 'delete', $request['id'] ) ) { + return new WP_Error( 'woocommerce_gzd_rest_cannot_delete', _x( 'Sorry, you are not allowed to delete this resource.', 'shipments', 'woocommerce-germanized' ), array( 'status' => rest_authorization_required_code() ) ); + } + + return true; + } + + /** + * Deletes one item from the collection. + * + * @param WP_REST_Request $request Full details about the request. + * + * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. + * @since 4.7.0 + */ + public function delete_item( $request ) { + $force = (bool) $request['force']; + $shipment = $this->get_shipment( (int) $request['id'] ); + + if ( ! $shipment ) { + return new WP_Error( 'woocommerce_gzd_rest_shipment_invalid_id', _x( 'Invalid ID.', 'shipments', 'woocommerce-germanized' ), array( 'status' => 404 ) ); + } + + if ( ! $shipment->delete( $force ) ) { + return new WP_Error( 'woocommerce_gzd_rest_cannot_delete', _x( 'The shipment cannot be deleted.', 'shipments', 'woocommerce-germanized' ), array( 'status' => 500 ) ); + } + + return rest_ensure_response( self::prepare_shipment( $shipment ) ); + } + + /** + * Checks if a given request has access to get a specific item. + * + * @param WP_REST_Request $request Full details about the request. + * + * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. + * @since 4.7.0 + */ + public function get_label_permissions_check( $request ) { + if ( ! $this->check_permissions( 'shipment_label', 'read', $request['id'] ) ) { + return new WP_Error( 'woocommerce_gzd_rest_cannot_view', _x( 'Sorry, you are not allowed to view this resource.', 'shipments', 'woocommerce-germanized' ), array( 'status' => rest_authorization_required_code() ) ); + } + + return true; + } + + /** + * Retrieves one item from the collection. + * + * @param WP_REST_Request $request Full details about the request. + * + * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. + * @since 4.7.0 + */ + public function get_label( $request ) { + $shipment = $this->get_shipment( (int) $request['id'] ); + + if ( ! $shipment ) { + return new WP_Error( 'woocommerce_gzd_rest_shipment_invalid_id', _x( 'Invalid ID.', 'shipments', 'woocommerce-germanized' ), array( 'status' => 404 ) ); + } + + $label = $shipment->get_label(); + + if ( ! $label ) { + return new WP_Error( 'woocommerce_gzd_rest_shipment_invalid_id', _x( 'Invalid ID.', 'shipments', 'woocommerce-germanized' ), array( 'status' => 404 ) ); + } + + $label_data = self::prepare_label( $label ); + + return rest_ensure_response( $label_data ); + } + + public function delete_label( $request ) { + $force = (bool) $request['force']; + $shipment = $this->get_shipment( (int) $request['id'] ); + + if ( ! $shipment ) { + return new WP_Error( 'woocommerce_gzd_rest_shipment_invalid_id', _x( 'Invalid ID.', 'shipments', 'woocommerce-germanized' ), array( 'status' => 404 ) ); + } + + $label = $shipment->get_label(); + + if ( ! $label || ! $label->delete( $force ) ) { + return new WP_Error( 'woocommerce_gzd_rest_cannot_delete', _x( 'The label cannot be deleted.', 'shipments', 'woocommerce-germanized' ), array( 'status' => 500 ) ); + } + + return rest_ensure_response( self::prepare_label( $label ) ); + } + + public function create_label( $request ) { + $shipment = $this->get_shipment( (int) $request['id'] ); + + if ( ! $shipment ) { + return new WP_Error( 'woocommerce_gzd_rest_shipment_invalid_id', _x( 'Invalid ID.', 'shipments', 'woocommerce-germanized' ), array( 'status' => 404 ) ); + } + + if ( ! $shipment->supports_label() || ! $shipment->needs_label() ) { + return new WP_Error( 'woocommerce_gzd_rest_shipment_label_exists', _x( 'Label already exists, please delete first.', 'shipments', 'woocommerce-germanized' ), array( 'status' => 404 ) ); + } + + $request->set_param( 'context', 'edit' ); + + $args = wc_clean( wp_unslash( $request['args'] ) ); + $args = empty( $args ) ? false : $args; + $result = $shipment->create_label( $args ); + + if ( is_wp_error( $result ) ) { + $message = implode( ' | ', $result->get_error_messages() ); + + return new WP_Error( 'woocommerce_gzd_rest_shipment_label_create', $message, array( 'status' => 500 ) ); + } + + $label = $shipment->get_label(); + + if ( ! $label ) { + return new WP_Error( 'woocommerce_gzd_rest_shipment_label_create', _x( 'There was an error creating the label.', 'shipments', 'woocommerce-germanized' ), array( 'status' => 500 ) ); + } + + $response = self::prepare_label( $label, $request ); + $response = rest_ensure_response( $response ); + + $response->set_status( 201 ); + $response->header( 'Location', rest_url( sprintf( '/%s/%s/%d/label', $this->namespace, $this->rest_base, $label->get_shipment_id() ) ) ); + + return $response; + } + + /** + * Checks if a given request has access to create a specific item. + * + * @param WP_REST_Request $request Full details about the request. + * + * @return true|WP_Error True if the request has access to delete the item, WP_Error object otherwise. + * @since 4.7.0 + */ + public function create_label_permissions_check( $request ) { + if ( ! $this->check_permissions( 'shipment_label', 'create' ) ) { + return new WP_Error( 'woocommerce_gzd_rest_cannot_delete', _x( 'Sorry, you are not allowed to create resources.', 'shipments', 'woocommerce-germanized' ), array( 'status' => rest_authorization_required_code() ) ); + } + + return true; + } + + /** + * Checks if a given request has access to delete a specific item. + * + * @param WP_REST_Request $request Full details about the request. + * + * @return true|WP_Error True if the request has access to delete the item, WP_Error object otherwise. + * @since 4.7.0 + */ + public function delete_label_permissions_check( $request ) { + if ( ! $this->check_permissions( 'shipment_label', 'delete', $request['id'] ) ) { + return new WP_Error( 'woocommerce_gzd_rest_cannot_delete', _x( 'Sorry, you are not allowed to delete this resource.', 'shipments', 'woocommerce-germanized' ), array( 'status' => rest_authorization_required_code() ) ); + } + + return true; + } + + /** + * Retrieves the item's schema, conforming to JSON Schema. + * + * @return array Item schema data. + * @since 4.7.0 + */ + public function get_item_schema() { + return $this->add_additional_fields_schema( self::get_single_item_schema() ); + } + + /** + * @param Shipment $shipment + * @param string $context + * @param bool|int $dp + * + * @return array + */ + public static function prepare_shipment( $shipment, $context = 'view', $dp = false ) { + $item_data = array(); + + foreach ( $shipment->get_items() as $item ) { + $item_data[] = array( + 'id' => $item->get_id(), + 'name' => $item->get_name( $context ), + 'order_item_id' => $item->get_order_item_id( $context ), + 'product_id' => $item->get_product_id( $context ), + 'sku' => $item->get_sku( $context ), + 'quantity' => $item->get_quantity( $context ), + 'total' => wc_format_decimal( $item->get_total( $context ), $dp ), + 'subtotal' => wc_format_decimal( $item->get_subtotal( $context ), $dp ), + 'weight' => wc_format_decimal( $item->get_weight( $context ), $dp ), + 'dimensions' => array( + 'length' => wc_format_decimal( $item->get_length( $context ), $dp ), + 'width' => wc_format_decimal( $item->get_width( $context ), $dp ), + 'height' => wc_format_decimal( $item->get_height( $context ), $dp ), + ), + 'hs_code' => $item->get_hs_code( $context ), + 'manufacture_country' => $item->get_manufacture_country( $context ), + 'attributes' => $item->get_attributes( $context ), + 'meta_data' => $item->get_meta_data(), + ); + } + + return array( + 'id' => $shipment->get_id(), + 'shipment_number' => $shipment->get_shipment_number(), + 'date_created' => wc_rest_prepare_date_response( $shipment->get_date_created( $context ), false ), + 'date_created_gmt' => wc_rest_prepare_date_response( $shipment->get_date_created( $context ) ), + 'date_sent' => wc_rest_prepare_date_response( $shipment->get_date_sent( $context ), false ), + 'date_sent_gmt' => wc_rest_prepare_date_response( $shipment->get_date_sent( $context ) ), + 'est_delivery_date' => wc_rest_prepare_date_response( $shipment->get_est_delivery_date( $context ), false ), + 'est_delivery_date_gmt' => wc_rest_prepare_date_response( $shipment->get_est_delivery_date( $context ) ), + 'total' => wc_format_decimal( $shipment->get_total( $context ), $dp ), + 'subtotal' => wc_format_decimal( $shipment->get_subtotal( $context ), $dp ), + 'additional_total' => wc_format_decimal( $shipment->get_additional_total( $context ), $dp ), + 'order_id' => $shipment->get_order_id( $context ), + 'order_number' => $shipment->get_order_number(), + 'weight' => wc_format_decimal( $shipment->get_weight( $context ), $dp ), + 'content_weight' => wc_format_decimal( $shipment->get_content_weight(), $dp ), + 'weight_unit' => $shipment->get_weight_unit( $context ), + 'packaging_id' => $shipment->get_packaging_id( $context ), + 'packaging_weight' => $shipment->get_packaging_weight( $context ), + 'status' => $shipment->get_status( $context ), + 'tracking_id' => $shipment->get_tracking_id( $context ), + 'tracking_url' => $shipment->get_tracking_url(), + 'shipping_provider' => $shipment->get_shipping_provider( $context ), + 'content_dimensions' => array( + 'length' => wc_format_decimal( $shipment->get_content_length(), $dp ), + 'width' => wc_format_decimal( $shipment->get_content_width(), $dp ), + 'height' => wc_format_decimal( $shipment->get_content_height(), $dp ), + ), + 'dimensions' => array( + 'length' => wc_format_decimal( $shipment->get_length( $context ), $dp ), + 'width' => wc_format_decimal( $shipment->get_width( $context ), $dp ), + 'height' => wc_format_decimal( $shipment->get_height( $context ), $dp ), + ), + 'package_dimensions' => array( + 'length' => wc_format_decimal( $shipment->get_package_length(), $dp ), + 'width' => wc_format_decimal( $shipment->get_package_width(), $dp ), + 'height' => wc_format_decimal( $shipment->get_package_height(), $dp ), + ), + 'dimension_unit' => $shipment->get_dimension_unit( $context ), + 'address' => $shipment->get_address( $context ), + 'sender_address' => 'return' === $shipment->get_type() ? $shipment->get_sender_address( $context ) : array(), + 'is_customer_requested' => 'return' === $shipment->get_type() ? $shipment->get_is_customer_requested( $context ) : false, + 'items' => $item_data, + 'meta_data' => $shipment->get_meta_data(), + ); + } + + /** + * @param Label $label + * + * @return + */ + private static function get_label_file( $label, $file_type = '' ) { + $result = array( + 'file' => '', + 'filename' => $label->get_filename( $file_type ), + 'path' => $label->get_path( 'view', $file_type ), + 'type' => $file_type, + ); + + if ( $file = $label->get_file( $file_type ) ) { + try { + $content = file_get_contents( $file ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents + $result['file'] = chunk_split( base64_encode( $content ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode + } catch ( \Exception $ex ) { + $result['file'] = ''; + } + } + + return $result; + } + + /** + * @param Label $label + * @param string $context + * @param bool|int $dp + * + * @return array + */ + public static function prepare_label( $label, $context = 'view', $dp = false ) { + $label_data = array( + 'id' => $label->get_id(), + 'date_created' => wc_rest_prepare_date_response( $label->get_date_created( $context ), false ), + 'date_created_gmt' => wc_rest_prepare_date_response( $label->get_date_created( $context ) ), + 'weight' => wc_format_decimal( $label->get_weight( $context ), $dp ), + 'net_weight' => wc_format_decimal( $label->get_net_weight( $context ), $dp ), + 'dimensions' => array( + 'length' => wc_format_decimal( $label->get_length( $context ), $dp ), + 'width' => wc_format_decimal( $label->get_width( $context ), $dp ), + 'height' => wc_format_decimal( $label->get_height( $context ), $dp ), + ), + 'shipment_id' => $label->get_shipment_id( $context ), + 'parent_id' => $label->get_parent_id( $context ), + 'product_id' => $label->get_product_id( $context ), + 'number' => $label->get_number( $context ), + 'type' => $label->get_type(), + 'shipping_provider' => $label->get_shipping_provider( $context ), + 'created_via' => $label->get_created_via( $context ), + 'services' => $label->get_services( $context ), + 'additional_file_types' => array(), + 'files' => array( self::get_label_file( $label ) ), + ); + + foreach ( $label->get_additional_file_types() as $file_type ) { + if ( 'default' === $file_type ) { + continue; + } + + $label_file = self::get_label_file( $label, $file_type ); + + if ( ! empty( $label_file['file'] ) ) { + $label_data['files'][] = $label_file; + $label_data['additional_file_types'][] = $file_type; + } + } + + return $label_data; + } + + /** + * Get the query params for collections. + * + * @return array + */ + public function get_collection_params() { + $params = parent::get_collection_params(); + + $params['context']['default'] = 'view'; + + $params['offset'] = array( + 'description' => _x( 'Offset the result set by a specific number of items.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'integer', + 'sanitize_callback' => 'absint', + 'validate_callback' => 'rest_validate_request_arg', + ); + $params['order'] = array( + 'default' => 'desc', + 'description' => _x( 'Order sort attribute ascending or descending.', 'shipments', 'woocommerce-germanized' ), + 'enum' => array( 'asc', 'desc' ), + 'sanitize_callback' => 'sanitize_key', + 'type' => 'string', + 'validate_callback' => 'rest_validate_request_arg', + ); + $params['orderby'] = array( + 'default' => 'date_created', + 'description' => _x( 'Sort collection by object attribute.', 'shipments', 'woocommerce-germanized' ), + 'enum' => array( + 'country', + 'status', + 'tracking_id', + 'date_created', + 'order_id', + 'weight', + ), + 'sanitize_callback' => 'sanitize_key', + 'type' => 'string', + 'validate_callback' => 'rest_validate_request_arg', + ); + $params['order_id'] = array( + 'description' => _x( 'Limit result set to shipments belonging to a certain order id.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'integer', + 'sanitize_callback' => 'absint', + 'validate_callback' => 'rest_validate_request_arg', + ); + $params['status'] = array( + 'description' => _x( 'Limit result set to shipments having a certain status.', 'shipments', 'woocommerce-germanized' ), + 'enum' => self::get_shipment_statuses(), + 'sanitize_callback' => 'sanitize_key', + 'type' => 'string', + 'validate_callback' => 'rest_validate_request_arg', + ); + $params['type'] = array( + 'description' => _x( 'Limit result set to shipments of a certain type.', 'shipments', 'woocommerce-germanized' ), + 'default' => 'simple', + 'enum' => wc_gzd_get_shipment_types(), + 'sanitize_callback' => 'sanitize_key', + 'type' => 'string', + 'validate_callback' => 'rest_validate_request_arg', + ); + return $params; + } + + /** + * Get the schema of a single shipment + * + * @return array + */ + public static function get_single_item_schema() { + $weight_unit = get_option( 'woocommerce_weight_unit' ); + $dimension_unit = get_option( 'woocommerce_dimension_unit' ); + + return array( + 'description' => _x( 'Single shipment.', 'shipment', 'woocommerce-germanized' ), + 'context' => array( 'view', 'edit' ), + 'readonly' => false, + 'type' => 'object', + 'properties' => array( + 'id' => array( + 'description' => _x( 'Shipment ID.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'integer', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'shipment_number' => array( + 'description' => _x( 'Shipment number.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'order_id' => array( + 'description' => _x( 'Shipment order id.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'order_number' => array( + 'description' => _x( 'Shipment order number.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'status' => array( + 'description' => _x( 'Shipment status.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'enum' => self::get_shipment_statuses(), + ), + 'tracking_id' => array( + 'description' => _x( 'Shipment tracking id.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'tracking_url' => array( + 'description' => _x( 'Shipment tracking url.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'shipping_provider' => array( + 'description' => _x( 'Shipment shipping provider.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'date_created' => array( + 'description' => _x( "The date the shipment was created, in the site's timezone.", 'shipments', 'woocommerce-germanized' ), + 'type' => 'date-time', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'date_created_gmt' => array( + 'description' => _x( 'The date the shipment was created, as GMT.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'date-time', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'date_sent' => array( + 'description' => _x( "The date the shipment was sent, in the site's timezone.", 'shipments', 'woocommerce-germanized' ), + 'type' => 'date-time', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'date_sent_gmt' => array( + 'description' => _x( 'The date the shipment was sent, as GMT.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'date-time', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'est_delivery_date' => array( + 'description' => _x( "The estimated delivery date of the shipment, in the site's timezone.", 'shipments', 'woocommerce-germanized' ), + 'type' => 'date-time', + 'context' => array( 'view', 'edit' ), + ), + 'est_delivery_date_gmt' => array( + 'description' => _x( 'The estimated delivery date of the shipment, as GMT.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'date-time', + 'context' => array( 'view', 'edit' ), + ), + 'type' => array( + 'description' => _x( 'Shipment type, e.g. simple or return.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'enum' => wc_gzd_get_shipment_types(), + ), + 'is_customer_requested' => array( + 'description' => _x( 'Return shipment is requested by customer.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'boolean', + 'context' => array( 'view', 'edit' ), + ), + 'sender_address' => array( + 'description' => _x( 'Return sender address.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'object', + 'context' => array( 'view', 'edit' ), + 'properties' => array( + 'first_name' => array( + 'description' => _x( 'First name.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'last_name' => array( + 'description' => _x( 'Last name.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'company' => array( + 'description' => _x( 'Company name.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'address_1' => array( + 'description' => _x( 'Address line 1', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'address_2' => array( + 'description' => _x( 'Address line 2', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'city' => array( + 'description' => _x( 'City name.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'state' => array( + 'description' => _x( 'ISO code or name of the state, province or district.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'postcode' => array( + 'description' => _x( 'Postal code.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'country' => array( + 'description' => _x( 'Country code in ISO 3166-1 alpha-2 format.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'customs_reference_number' => array( + 'description' => _x( 'Customs reference number.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + ), + ), + 'weight' => array( + 'description' => _x( 'Shipment weight.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'content_weight' => array( + 'description' => _x( 'Shipment content weight.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'content_dimensions' => array( + 'description' => _x( 'Shipment content dimensions.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'object', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + 'properties' => array( + 'length' => array( + 'description' => _x( 'Shipment content length.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'width' => array( + 'description' => _x( 'Shipment content width.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'height' => array( + 'description' => _x( 'Shipment content height.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + ), + ), + 'weight_unit' => array( + 'description' => _x( 'Shipment weight unit.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'default' => $weight_unit, + ), + 'packaging_id' => array( + 'description' => _x( 'Shipment packaging id.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'integer', + 'context' => array( 'view', 'edit' ), + ), + 'packaging_weight' => array( + 'description' => _x( 'Shipment packaging weight.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'total' => array( + 'description' => _x( 'Shipment total.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'subtotal' => array( + 'description' => _x( 'Shipment subtotal.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'additional_total' => array( + 'description' => _x( 'Shipment additional total.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'version' => array( + 'description' => _x( 'Shipment version.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'shipping_method' => array( + 'description' => _x( 'Shipment shipping method.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'dimensions' => array( + 'description' => _x( 'Shipment dimensions.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'object', + 'context' => array( 'view', 'edit' ), + 'properties' => array( + 'length' => array( + 'description' => _x( 'Shipment length.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'width' => array( + 'description' => _x( 'Shipment width.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'height' => array( + 'description' => _x( 'Shipment height.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + ), + ), + 'package_dimensions' => array( + 'description' => _x( 'Shipment package dimensions.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'object', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + 'properties' => array( + 'length' => array( + 'description' => _x( 'Shipment package length.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'readonly' => true, + 'context' => array( 'view', 'edit' ), + ), + 'width' => array( + 'description' => _x( 'Shipment package width.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'readonly' => true, + 'context' => array( 'view', 'edit' ), + ), + 'height' => array( + 'description' => _x( 'Shipment package height.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'readonly' => true, + 'context' => array( 'view', 'edit' ), + ), + ), + ), + 'dimension_unit' => array( + 'description' => _x( 'Shipment dimension unit.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'default' => $dimension_unit, + ), + 'address' => array( + 'description' => _x( 'Shipping address.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'object', + 'context' => array( 'view', 'edit' ), + 'properties' => array( + 'first_name' => array( + 'description' => _x( 'First name.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'last_name' => array( + 'description' => _x( 'Last name.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'company' => array( + 'description' => _x( 'Company name.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'address_1' => array( + 'description' => _x( 'Address line 1', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'address_2' => array( + 'description' => _x( 'Address line 2', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'city' => array( + 'description' => _x( 'City name.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'state' => array( + 'description' => _x( 'ISO code or name of the state, province or district.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'postcode' => array( + 'description' => _x( 'Postal code.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'country' => array( + 'description' => _x( 'Country code in ISO 3166-1 alpha-2 format.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'customs_reference_number' => array( + 'description' => _x( 'Customs reference number.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + ), + ), + 'meta_data' => array( + 'description' => _x( 'Meta data.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'array', + 'context' => array( 'view', 'edit' ), + 'items' => array( + 'type' => 'object', + 'properties' => array( + 'id' => array( + 'description' => _x( 'Meta ID.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'integer', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'key' => array( + 'description' => _x( 'Meta key.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'value' => array( + 'description' => _x( 'Meta value.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'mixed', + 'context' => array( 'view', 'edit' ), + ), + ), + ), + ), + 'items' => array( + 'description' => _x( 'Shipment items.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'array', + 'context' => array( 'view', 'edit' ), + 'items' => array( + 'type' => 'object', + 'properties' => array( + 'id' => array( + 'description' => _x( 'Item ID.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'integer', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'name' => array( + 'description' => _x( 'Item name.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'mixed', + 'context' => array( 'view', 'edit' ), + ), + 'order_item_id' => array( + 'description' => _x( 'Order Item ID.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'integer', + 'context' => array( 'view', 'edit' ), + ), + 'product_id' => array( + 'description' => _x( 'Product ID.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'mixed', + 'context' => array( 'view', 'edit' ), + ), + 'quantity' => array( + 'description' => _x( 'Quantity.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'integer', + 'context' => array( 'view', 'edit' ), + ), + 'weight' => array( + 'description' => _x( 'Item weight.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'sku' => array( + 'description' => _x( 'Item SKU.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'total' => array( + 'description' => _x( 'Item total.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'subtotal' => array( + 'description' => _x( 'Item subtotal.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'hs_code' => array( + 'description' => _x( 'Item HS Code (customs).', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'manufacture_country' => array( + 'description' => _x( 'Item country of manufacture in ISO 3166-1 alpha-2 format.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'dimensions' => array( + 'description' => _x( 'Item dimensions.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'object', + 'context' => array( 'view', 'edit' ), + 'properties' => array( + 'length' => array( + 'description' => _x( 'Item length.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'width' => array( + 'description' => _x( 'Item width.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'height' => array( + 'description' => _x( 'Item height.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + ), + ), + 'attributes' => array( + 'description' => _x( 'Item attributes.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'object', + 'context' => array( 'view', 'edit' ), + 'properties' => array( + 'key' => array( + 'description' => _x( 'Attribute key.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'value' => array( + 'description' => _x( 'Attribute value.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'label' => array( + 'description' => _x( 'Attribute label.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'order_item_meta_id' => array( + 'description' => _x( 'Order item meta id.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'integer', + 'context' => array( 'view', 'edit' ), + ), + ), + ), + 'meta_data' => array( + 'description' => _x( 'Shipment item meta data.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'array', + 'context' => array( 'view', 'edit' ), + 'items' => array( + 'type' => 'object', + 'properties' => array( + 'id' => array( + 'description' => _x( 'Meta ID.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'integer', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'key' => array( + 'description' => _x( 'Meta key.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'value' => array( + 'description' => _x( 'Meta value.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'mixed', + 'context' => array( 'view', 'edit' ), + ), + ), + ), + ), + ), + ), + ), + ), + ); + } + + public function get_public_item_label_schema() { + return array( + 'description' => _x( 'Shipment label.', 'shipment', 'woocommerce-germanized' ), + 'context' => array( 'view', 'edit' ), + 'readonly' => false, + 'type' => 'object', + 'properties' => array( + 'id' => array( + 'description' => _x( 'Label ID.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'integer', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'date_created' => array( + 'description' => _x( "The date the label was created, in the site's timezone.", 'shipments', 'woocommerce-germanized' ), + 'type' => 'date-time', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'date_created_gmt' => array( + 'description' => _x( 'The date the label was created, as GMT.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'date-time', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'shipment_id' => array( + 'description' => _x( 'Shipment id.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'integer', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'parent_id' => array( + 'description' => _x( 'Parent id.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'integer', + 'context' => array( 'view', 'edit' ), + ), + 'product_id' => array( + 'description' => _x( 'Label product id.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'number' => array( + 'description' => _x( 'Label number.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'shipping_provider' => array( + 'description' => _x( 'Shipping provider.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'weight' => array( + 'description' => _x( 'Weight.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'net_weight' => array( + 'description' => _x( 'Net weight.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'created_via' => array( + 'description' => _x( 'Created via.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'is_trackable' => array( + 'description' => _x( 'Is trackable?', 'shipments', 'woocommerce-germanized' ), + 'type' => 'boolean', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'additional_file_types' => array( + 'description' => _x( 'Additional file types', 'shipments', 'woocommerce-germanized' ), + 'type' => 'array', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + 'items' => array( + 'type' => 'string', + ), + ), + 'files' => array( + 'description' => _x( 'Label file data.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'array', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + 'items' => array( + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + 'type' => 'object', + 'properties' => array( + 'path' => array( + 'description' => _x( 'File path.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'filename' => array( + 'description' => _x( 'File name.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'file' => array( + 'description' => _x( 'The file data (base64 encoded).', 'shipments', 'woocommerce-germanized' ), + 'type' => 'binary', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'type' => array( + 'description' => _x( 'File type.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + ), + ), + ), + 'type' => array( + 'description' => _x( 'Label type, e.g. simple or return.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'dimensions' => array( + 'description' => _x( 'Label dimensions.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'object', + 'context' => array( 'view', 'edit' ), + 'properties' => array( + 'length' => array( + 'description' => _x( 'Label length.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'width' => array( + 'description' => _x( 'Label width.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'height' => array( + 'description' => _x( 'Label height.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + ), + ), + 'services' => array( + 'description' => _x( 'Label services.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'array', + 'context' => array( 'view', 'edit' ), + 'items' => array( + 'type' => 'string', + ), + ), + 'meta_data' => array( + 'description' => _x( 'Label meta data.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'array', + 'context' => array( 'view', 'edit' ), + 'items' => array( + 'type' => 'object', + 'properties' => array( + 'id' => array( + 'description' => _x( 'Meta ID.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'integer', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'key' => array( + 'description' => _x( 'Meta key.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'value' => array( + 'description' => _x( 'Meta value.', 'shipments', 'woocommerce-germanized' ), + 'type' => 'mixed', + 'context' => array( 'view', 'edit' ), + ), + ), + ), + ), + ), + ); + } +} diff --git a/packages/woocommerce-germanized-shipments/src/ReturnReason.php b/packages/woocommerce-germanized-shipments/src/ReturnReason.php new file mode 100644 index 000000000..2b89c904c --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/ReturnReason.php @@ -0,0 +1,46 @@ + '', + 'reason' => '', + 'order' => 0, + ) + ); + + $this->args = $args; + } + + public function get_reason() { + return $this->args['reason']; + } + + public function get_code() { + return $this->args['code']; + } + + public function get_name() { + return $this->get_code(); + } + + public function get_order() { + return absint( $this->args['order'] ); + } +} diff --git a/packages/woocommerce-germanized-shipments/src/ReturnShipment.php b/packages/woocommerce-germanized-shipments/src/ReturnShipment.php new file mode 100644 index 000000000..64ad411fe --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/ReturnShipment.php @@ -0,0 +1,478 @@ + 0, + 'is_customer_requested' => false, + 'sender_address' => array(), + ); + + /** + * Returns the shipment type. + * + * @return string + */ + public function get_type() { + return 'return'; + } + + /** + * Returns the order id belonging to the shipment. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return integer + */ + public function get_order_id( $context = 'view' ) { + return $this->get_prop( 'order_id', $context ); + } + + /** + * Returns whether the current return was requested by a customer or not. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return boolean + */ + public function get_is_customer_requested( $context = 'view' ) { + return $this->get_prop( 'is_customer_requested', $context ); + } + + public function is_customer_requested() { + return $this->get_is_customer_requested(); + } + + public function confirm_customer_request() { + if ( $this->is_customer_requested() && $this->has_status( 'requested' ) ) { + + $this->set_status( 'processing' ); + + if ( $this->save() ) { + /** + * Action that fires after a return request has been confirmed to the customer. + * + * @param integer $shipment_id The return shipment id. + * @param ReturnShipment $shipment The return shipment object. + * + * @since 3.1.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_return_shipment_customer_confirmed', $this->get_id(), $this ); + + return true; + } else { + return false; + } + } + + return false; + } + + /** + * Returns the address of the sender e.g. customer. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string[] + */ + public function get_sender_address( $context = 'view' ) { + return $this->get_prop( 'sender_address', $context ); + } + + /** + * Set shipment order id. + * + * @param string $order_id The order id. + */ + public function set_order_id( $order_id ) { + // Reset order object + $this->order = null; + + $this->set_prop( 'order_id', absint( $order_id ) ); + } + + /** + * Set if the current return was requested by the customer or not. + * + * @param string $is_requested Whether or not it is requested by the customer. + */ + public function set_is_customer_requested( $is_requested ) { + $this->set_prop( 'is_customer_requested', wc_string_to_bool( $is_requested ) ); + } + + /** + * Set shipment order. + * + * @param Order $order_shipment The order shipment. + */ + public function set_order_shipment( &$order_shipment ) { + $this->order_shipment = $order_shipment; + } + + /** + * Returns shipment order. + * + * @return Order|null The order shipment. + */ + public function get_order_shipment() { + if ( is_null( $this->order_shipment ) ) { + $order = $this->get_order(); + $this->order_shipment = ( $order ? wc_gzd_get_shipment_order( $order ) : false ); + } + + return $this->order_shipment; + } + + /** + * Returns the shippable item count. + * + * @return int + */ + public function get_shippable_item_count() { + + if ( $order_shipment = $this->get_order_shipment() ) { + return $order_shipment->get_returnable_item_count(); + } + + return 0; + } + + /** + * Tries to fetch the order for the current shipment. + * + * @return bool|WC_Order|null + */ + public function get_order() { + if ( is_null( $this->order ) ) { + $this->order = ( $this->get_order_id() > 0 ? wc_get_order( $this->get_order_id() ) : false ); + } + + return $this->order; + } + + /** + * Returns available shipment methods by checking the corresponding order. + * + * @return string[] + */ + public function get_available_shipping_methods() { + $methods = array(); + $methods[ $this->get_shipping_method() ] = ''; + + return $methods; + } + + /** + * Returns a sender address prop. + * + * @param string $prop + * @param string $context + * + * @return null|string + */ + protected function get_sender_address_prop( $prop, $context = 'view' ) { + $value = null; + + if ( isset( $this->changes['sender_address'][ $prop ] ) || isset( $this->data['sender_address'][ $prop ] ) ) { + $value = isset( $this->changes['sender_address'][ $prop ] ) ? $this->changes['sender_address'][ $prop ] : $this->data['sender_address'][ $prop ]; + + if ( 'view' === $context ) { + /** + * Filter to adjust a Shipment's return sender address property e.g. first_name. + * + * The dynamic portion of this hook, `$this->get_hook_prefix()` is used to construct a + * unique hook for a shipment type. `$prop` refers to the actual address property e.g. first_name. + * + * Example hook name: woocommerce_gzd_return_shipment_get_sender_address_first_name + * + * @param string $value The address property value. + * @param Shipment $this The shipment object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + $value = apply_filters( "{$this->get_hook_prefix()}sender_address_{$prop}", $value, $this ); + } + } + + return $value; + } + + /** + * Set sender address. + * + * @param string[] $address The address props. + */ + public function set_sender_address( $address ) { + $this->set_prop( 'sender_address', empty( $address ) ? array() : (array) $address ); + } + + /** + * Syncs the return shipment with the corresponding parent shipment. + * + * @param array $args + * + * @return bool + */ + public function sync( $args = array() ) { + try { + if ( ! $order_shipment = $this->get_order_shipment() ) { + throw new Exception( _x( 'Invalid shipment order', 'shipments', 'woocommerce-germanized' ) ); + } + + $return_address = wc_gzd_get_shipment_return_address( $order_shipment ); + $order = $order_shipment->get_order(); + + /** + * Make sure that manually adjusted providers are not overridden by syncing. + */ + $default_provider = $order_shipment->get_default_return_shipping_provider(); + $provider = $this->get_shipping_provider( 'edit' ); + $sender_address_data = array_merge( + ( $order->has_shipping_address() ? $order->get_address( 'shipping' ) : $order->get_address( 'billing' ) ), + array( + 'email' => $order->get_billing_email(), + 'phone' => $order->get_billing_phone(), + ) + ); + + // Prefer shipping phone in case exists + if ( is_callable( array( $order, 'get_shipping_phone' ) ) && $order->get_shipping_phone() ) { + $sender_address_data['phone'] = $order->get_shipping_phone(); + } + + $args = wp_parse_args( + $args, + array( + 'order_id' => $order->get_id(), + 'country' => $return_address['country'], + 'shipping_method' => wc_gzd_get_shipment_order_shipping_method_id( $order ), + 'shipping_provider' => ( ! empty( $provider ) ) ? $provider : $default_provider, + 'address' => $return_address, + 'sender_address' => $sender_address_data, + 'weight' => $this->get_weight( 'edit' ), + 'length' => $this->get_length( 'edit' ), + 'width' => $this->get_width( 'edit' ), + 'height' => $this->get_height( 'edit' ), + ) + ); + + /** + * Filter to allow adjusting the return shipment props synced from the corresponding order. + * + * @param mixed $args The properties in key => value pairs. + * @param ReturnShipment $shipment The shipment object. + * @param Order $order_shipment The shipment order object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + $args = apply_filters( 'woocommerce_gzd_return_shipment_sync_props', $args, $this, $order_shipment ); + + $this->set_props( $args ); + + /** + * Action that fires after a return shipment has been synced. Syncing is used to + * keep the shipment in sync with the corresponding parent shipment. + * + * @param ReturnShipment $shipment The return shipment object. + * @param Order $order_shipment The shipment order object. + * @param array $args Array containing properties in key => value pairs to be updated. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_return_shipment_synced', $this, $order_shipment, $args ); + + } catch ( Exception $e ) { + return false; + } + + return true; + } + + /** + * Keeps items in sync with the parent shipment items. + * Limits quantities and removes non-existent items. + * + * @param array $args + * + * @return bool + */ + public function sync_items( $args = array() ) { + try { + + if ( ! $order_shipment = $this->get_order_shipment() ) { + throw new Exception( _x( 'Invalid shipment order', 'shipments', 'woocommerce-germanized' ) ); + } + + $order = $order_shipment->get_order(); + + $args = wp_parse_args( + $args, + array( + 'items' => array(), + ) + ); + + $available_items = $order_shipment->get_available_items_for_return( + array( + 'shipment_id' => $this->get_id(), + 'exclude_current_shipment' => true, + ) + ); + + foreach ( $available_items as $order_item_id => $item_data ) { + + if ( $item = $order_shipment->get_simple_shipment_item( $order_item_id ) ) { + $quantity = $item_data['max_quantity']; + $return_reason_code = ''; + + if ( ! empty( $args['items'] ) ) { + if ( isset( $args['items'][ $order_item_id ] ) ) { + + if ( is_array( $args['items'][ $order_item_id ] ) ) { + $default_item_data = wp_parse_args( + $args['items'][ $order_item_id ], + array( + 'quantity' => 1, + 'return_reason_code' => '', + ) + ); + } else { + $default_item_data = array( + 'quantity' => absint( $args['items'][ $order_item_id ] ), + 'return_reason_code' => '', + ); + } + + $new_quantity = $default_item_data['quantity']; + $return_reason_code = $default_item_data['return_reason_code']; + + if ( $new_quantity < $quantity ) { + $quantity = $new_quantity; + } + } else { + continue; + } + } + + if ( $quantity <= 0 ) { + continue; + } + + $sync_data = array( + 'quantity' => $quantity, + ); + + if ( ! empty( $return_reason_code ) ) { + $sync_data['return_reason_code'] = $return_reason_code; + } + + if ( ! $shipment_item = $this->get_item_by_order_item_id( $order_item_id ) ) { + $shipment_item = wc_gzd_create_return_shipment_item( $this, $item, $sync_data ); + + $this->add_item( $shipment_item ); + } else { + $shipment_item->sync( $sync_data ); + } + } + } + + foreach ( $this->get_items() as $item ) { + + // Remove non-existent items + if ( ! $shipment_item = $order_shipment->get_simple_shipment_item( $item->get_order_item_id() ) ) { + $this->remove_item( $item->get_id() ); + } + } + + // Sync packaging + $this->sync_packaging(); + + /** + * Action that fires after items of a shipment have been synced. + * + * @param SimpleShipment $shipment The shipment object. + * @param Order $order_shipment The shipment order object. + * @param array $args Array containing additional data e.g. items. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_return_shipment_items_synced', $this, $order_shipment, $args ); + + } catch ( Exception $e ) { + return false; + } + + return true; + } + + /** + * Returns whether the Shipment needs additional items or not. + * + * @param bool|integer[] $available_items + * + * @return bool + */ + public function needs_items( $available_items = false ) { + + if ( ! $available_items && ( $order_shipment = $this->get_order_shipment() ) ) { + $available_items = array_keys( $order_shipment->get_available_items_for_return() ); + } + + return ( $this->is_editable() && ! $this->contains_order_item( $available_items ) ); + } + + /** + * Returns the edit shipment URL. + * + * @return mixed|string|void + */ + public function get_edit_shipment_url() { + /** + * Filter to adjust the edit Shipment admin URL. + * + * The dynamic portion of this hook, `$this->get_hook_prefix()` is used to construct a + * unique hook for a shipment type. + * + * Example hook name: woocommerce_gzd_shipment_get_edit_url + * + * @param string $url The URL. + * @param Shipment $this The shipment object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( "{$this->get_hook_prefix()}edit_url", get_admin_url( null, 'post.php?post=' . $this->get_order_id() . '&action=edit&shipment_id=' . $this->get_id() ), $this ); + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Shipment.php b/packages/woocommerce-germanized-shipments/src/Shipment.php new file mode 100644 index 000000000..5f3c52415 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Shipment.php @@ -0,0 +1,2770 @@ + null, + 'date_sent' => null, + 'status' => '', + 'weight' => '', + 'width' => '', + 'height' => '', + 'length' => '', + 'packaging_weight' => '', + 'weight_unit' => '', + 'dimension_unit' => '', + 'country' => '', + 'address' => array(), + 'tracking_id' => '', + 'shipping_provider' => '', + 'shipping_method' => '', + 'total' => 0, + 'subtotal' => 0, + 'additional_total' => 0, + 'est_delivery_date' => null, + 'packaging_id' => 0, + 'version' => '', + ); + + /** + * Get the shipment if ID is passed, otherwise the shipment is new and empty. + * This class should NOT be instantiated, but the `wc_gzd_get_shipment` function should be used. + * + * @param int|object|Shipment $shipment Shipment to read. + */ + public function __construct( $data = 0 ) { + parent::__construct( $data ); + + if ( $data instanceof Shipment ) { + $this->set_id( absint( $data->get_id() ) ); + } elseif ( is_numeric( $data ) ) { + $this->set_id( $data ); + } + + $this->data_store = WC_Data_Store::load( $this->data_store_name ); + + // If we have an ID, load the user from the DB. + if ( $this->get_id() ) { + try { + $this->data_store->read( $this ); + } catch ( Exception $e ) { + $this->set_id( 0 ); + $this->set_object_read( true ); + } + } else { + $this->set_object_read( true ); + } + } + + public function get_type() { + return ''; + } + + /** + * Merge changes with data and clear. + * Overrides WC_Data::apply_changes. + * + * @since 3.2.0 + */ + public function apply_changes() { + if ( function_exists( 'array_replace' ) ) { + $this->data = array_replace( $this->data, $this->changes ); // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctions.array_replaceFound + } else { // PHP 5.2 compatibility. + foreach ( $this->changes as $key => $change ) { + $this->data[ $key ] = $change; + } + } + $this->changes = array(); + } + + /** + * @return bool|Order + */ + public function get_order_shipment() { + return false; + } + + public function set_order_shipment( &$order_shipment ) {} + + /** + * Return item count (quantities summed up). + * + * @return int + */ + public function get_item_count() { + $items = $this->get_items(); + $quantity = 0; + + foreach ( $items as $item ) { + $quantity += $item->get_quantity(); + } + + return $quantity; + } + + /** + * Prefix for action and filter hooks on data. + * + * @return string + */ + protected function get_hook_prefix() { + return $this->get_general_hook_prefix() . 'get_'; + } + + /** + * Prefix for action and filter hooks on data. + * + * @return string + */ + protected function get_general_hook_prefix() { + $shipment_prefix = 'simple' === $this->get_type() ? '' : $this->get_type() . '_'; + + return "woocommerce_gzd_{$shipment_prefix}shipment_"; + } + + public function is_shipping_domestic() { + return Package::is_shipping_domestic( + $this->get_country(), + array( + 'sender_country' => $this->get_sender_country(), + 'sender_postcode' => $this->get_sender_postcode(), + 'postcode' => $this->get_postcode(), + ) + ); + } + + /** + * Returns true in case the shipment is being shipped inner EU, e.g. + * from a base country inside of the EU to another country inside the EU. + * + * @return bool + */ + public function is_shipping_inner_eu() { + if ( Package::is_shipping_inner_eu_country( + $this->get_country(), + array( + 'sender_country' => $this->get_sender_country(), + 'sender_postcode' => $this->get_sender_postcode(), + 'postcode' => $this->get_postcode(), + ) + ) ) { + return true; + } + + return false; + } + + public function is_shipping_international() { + if ( $this->is_shipping_domestic() || $this->is_shipping_inner_eu() ) { + return false; + } + + return true; + } + + /** + * Return the shipment statuses without gzd- internal prefix. + * + * @param string $context View or edit context. + * @return string + */ + public function get_status( $context = 'view' ) { + $status = $this->get_prop( 'status', $context ); + + if ( empty( $status ) && 'view' === $context ) { + + /** + * Filters the default Shipment status used as fallback. + * + * The dynamic portion of this hook, `$this->get_hook_prefix()` is used to construct a + * unique hook for a shipment type. + * + * Example hook name: woocommerce_gzd_shipment_get_default_shipment_status + * + * @param string $status Default fallback status. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + $status = apply_filters( "{$this->get_hook_prefix()}}default_shipment_status", 'draft' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores + } + + return $status; + } + + /** + * Checks whether the shipment has a specific status or not. + * + * @param string|string[] $status The status to be checked against. + * @return boolean + */ + public function has_status( $status ) { + /** + * Filter to decide whether a Shipment has a certain status or not. + * + * @param boolean $has_status Whether the Shipment has a status or not. + * @param Shipment $this The shipment object. + * @param string $status The status to be checked against. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipment_has_status', ( is_array( $status ) && in_array( $this->get_status(), $status, true ) ) || $this->get_status() === $status, $this, $status ); + } + + /** + * Return the date this shipment was created. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return WC_DateTime|null object if the date is set or null if there is no date. + */ + public function get_date_created( $context = 'view' ) { + return $this->get_prop( 'date_created', $context ); + } + + /** + * Return the date this shipment was sent. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return WC_DateTime|null object if the date is set or null if there is no date. + */ + public function get_date_sent( $context = 'view' ) { + return $this->get_prop( 'date_sent', $context ); + } + + /** + * Returns the shipment method. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_shipping_method( $context = 'view' ) { + return $this->get_prop( 'shipping_method', $context ); + } + + public function get_shipping_method_instance() { + $method_id = $this->get_shipping_method(); + + if ( is_null( $this->shipping_method_instance ) && ! empty( $method_id ) ) { + $this->shipping_method_instance = wc_gzd_get_shipping_provider_method( $this->get_shipping_method() ); + } + + return is_null( $this->shipping_method_instance ) ? false : $this->shipping_method_instance; + } + + /** + * Returns the shipment weight. In case view context was chosen and weight is not yet set, returns the content weight. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_weight( $context = 'view' ) { + $weight = $this->get_prop( 'weight', $context ); + + if ( 'view' === $context && '' === $weight ) { + return $this->get_content_weight(); + } + + return $weight; + } + + public function get_total_weight() { + $weight = $this->get_weight() + $this->get_packaging_weight(); + + return $weight; + } + + public function get_packaging_weight( $context = 'view' ) { + $weight = $this->get_prop( 'packaging_weight', $context ); + + if ( 'view' === $context && '' === $weight ) { + $weight = wc_format_decimal( 0 ); + + if ( $packaging = $this->get_packaging() ) { + if ( ! empty( $packaging->get_weight() ) ) { + $weight = wc_get_weight( $packaging->get_weight(), $this->get_weight_unit(), wc_gzd_get_packaging_weight_unit() ); + } + } + } + + return $weight; + } + + public function get_items_to_pack() { + if ( ! Package::is_packing_supported() ) { + return $this->get_items(); + } else { + if ( is_null( $this->items_to_pack ) ) { + $this->items_to_pack = array(); + + foreach ( $this->get_items() as $item ) { + for ( $i = 0; $i < $item->get_quantity(); $i++ ) { // phpcs:ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall.NotAllowed + $box_item = new Packing\ShipmentItem( $item ); + $this->items_to_pack[] = $box_item; + } + } + } + + return apply_filters( "{$this->get_hook_prefix()}items_to_pack", $this->items_to_pack, $this ); + } + } + + /** + * Returns the shipment weight unit. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_weight_unit( $context = 'view' ) { + $unit = $this->get_prop( 'weight_unit', $context ); + + if ( 'view' === $context && '' === $unit ) { + return get_option( 'woocommerce_weight_unit' ); + } + + return $unit; + } + + /** + * Returns the shipment dimension unit. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_dimension_unit( $context = 'view' ) { + $unit = $this->get_prop( 'dimension_unit', $context ); + + if ( 'view' === $context && '' === $unit ) { + return get_option( 'woocommerce_dimension_unit' ); + } + + return $unit; + } + + /** + * Returns the shipment length. In case view context was chosen and length is not yet set, returns the content length. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_length( $context = 'view' ) { + $length = $this->get_prop( 'length', $context ); + + if ( 'view' === $context && '' === $length ) { + return $this->get_content_length(); + } + + return $length; + } + + public function get_package_length() { + $length = $this->get_length(); + + // Older versions did not sync dimensions with packaging dimensions + if ( '' === $this->get_version() ) { + if ( $packaging = $this->get_packaging() ) { + $length = wc_get_dimension( $packaging->get_length(), $this->get_dimension_unit(), wc_gzd_get_packaging_dimension_unit() ); + } + } + + return $length; + } + + public function has_packaging() { + return ( $this->get_packaging_id() > 0 && $this->get_packaging() ) ? true : false; + } + + /** + * Returns the shipment width. In case view context was chosen and width is not yet set, returns the content width. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_width( $context = 'view' ) { + $width = $this->get_prop( 'width', $context ); + + if ( 'view' === $context && '' === $width ) { + return $this->get_content_width(); + } + + return $width; + } + + public function get_package_width() { + $width = $this->get_width(); + + if ( '' === $this->get_version() ) { + if ( $packaging = $this->get_packaging() ) { + $width = wc_get_dimension( $packaging->get_width(), $this->get_dimension_unit(), wc_gzd_get_packaging_dimension_unit() ); + } + } + + return $width; + } + + /** + * Returns the shipment height. In case view context was chosen and height is not yet set, returns the content height. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_height( $context = 'view' ) { + $height = $this->get_prop( 'height', $context ); + + if ( 'view' === $context && '' === $height ) { + return $this->get_content_height(); + } + + return $height; + } + + public function get_package_height() { + $height = $this->get_height(); + + if ( '' === $this->get_version() ) { + if ( $packaging = $this->get_packaging() ) { + $height = wc_get_dimension( $packaging->get_height(), $this->get_dimension_unit(), wc_gzd_get_packaging_dimension_unit() ); + } + } + + return $height; + } + + public function has_dimensions() { + $width = $this->get_width(); + $length = $this->get_length(); + $height = $this->get_height(); + + return ( ! empty( $width ) && ! empty( $length ) && ! empty( $height ) ); + } + + /** + * Returns the calculated weights for included items. + * + * @return float[] + */ + public function get_item_weights() { + if ( is_null( $this->weights ) ) { + $this->weights = array(); + + foreach ( $this->get_items() as $item ) { + $this->weights[ $item->get_id() ] = ( ( $item->get_weight() === '' ? 0 : $item->get_weight() ) * $item->get_quantity() ); + } + + if ( empty( $this->weights ) ) { + $this->weights = array( 0 ); + } + } + + return $this->weights; + } + + /** + * Returns the calculated lengths for included items. + * + * @return float[] + */ + public function get_item_lengths() { + if ( is_null( $this->lengths ) ) { + $this->lengths = array(); + + foreach ( $this->get_items() as $item ) { + $this->lengths[ $item->get_id() ] = $item->get_length() === '' ? 0 : $item->get_length(); + } + + if ( empty( $this->lengths ) ) { + $this->lengths = array( 0 ); + } + } + + return $this->lengths; + } + + public function get_item_volumes() { + if ( is_null( $this->volumes ) ) { + $this->volumes = array(); + + foreach ( $this->get_items() as $item ) { + $dimensions = $item->get_dimensions(); + $volume = ( '' !== $dimensions['length'] ? (float) $dimensions['length'] : 0 ) * ( '' !== $dimensions['width'] ? (float) $dimensions['width'] : 0 ) * ( '' !== $dimensions['height'] ? (float) $dimensions['height'] : 0 ); + + $this->volumes[ $item->get_id() ] = $volume * (float) $item->get_quantity(); + } + + if ( empty( $this->volumes ) ) { + $this->volumes = array( 0 ); + } + } + + return $this->volumes; + } + + /** + * Returns the calculated widths for included items. + * + * @return float[] + */ + public function get_item_widths() { + if ( is_null( $this->widths ) ) { + $this->widths = array(); + + foreach ( $this->get_items() as $item ) { + $this->widths[ $item->get_id() ] = $item->get_width() === '' ? 0 : $item->get_width(); + } + + if ( empty( $this->widths ) ) { + $this->widths = array( 0 ); + } + } + + return $this->widths; + } + + /** + * Returns the calculated heights for included items. + * + * @return float[] + */ + public function get_item_heights() { + if ( is_null( $this->heights ) ) { + $this->heights = array(); + + foreach ( $this->get_items() as $item ) { + $this->heights[ $item->get_id() ] = ( $item->get_height() === '' ? 0 : $item->get_height() ) * $item->get_quantity(); + } + + if ( empty( $this->heights ) ) { + $this->heights = array( 0 ); + } + } + + return $this->heights; + } + + /** + * Returns the calculated weight for included items. + * + * @return float + */ + public function get_content_weight() { + return wc_format_decimal( array_sum( $this->get_item_weights() ) ); + } + + public function get_content_dimensions() { + return array( + 'length' => $this->get_content_length(), + 'width' => $this->get_content_width(), + 'height' => $this->get_content_height(), + ); + } + + /** + * Returns the calculated length for included items. + * + * @return float + */ + public function get_content_length() { + $default = max( $this->get_item_lengths() ); + + return wc_format_decimal( $default, false, true ); + } + + /** + * Returns the calculated width for included items. + * + * @return float + */ + public function get_content_width() { + $default = max( $this->get_item_widths() ); + + return wc_format_decimal( $default, false, true ); + } + + /** + * Returns the calculated volume for included items. + * + * @return float + */ + public function get_content_volume() { + $default = array_sum( $this->get_item_volumes() ); + + return wc_format_decimal( $default, false, true ); + } + + /** + * Returns the calculated height for included items. + * + * @return float + */ + public function get_content_height() { + $default_height = array_sum( $this->get_item_heights() ); + + return wc_format_decimal( $default_height, false, true ); + } + + /** + * Returns the shipping address properties. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string[] + */ + public function get_address( $context = 'view' ) { + return $this->get_prop( 'address', $context ); + } + + /** + * Returns the shipment total. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return float + */ + public function get_total( $context = 'view' ) { + return $this->get_prop( 'total', $context ); + } + + /** + * Returns the shipment total. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return float + */ + public function get_subtotal( $context = 'view' ) { + $subtotal = $this->get_prop( 'subtotal', $context ); + + if ( 'view' === $context && empty( $subtotal ) ) { + $subtotal = $this->get_total(); + } + + return $subtotal; + } + + /** + * Returns the additional total amount containing shipping and fee costs. + * Only one of the shipments related to an order should include additional total. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return float + */ + public function get_additional_total( $context = 'view' ) { + return $this->get_prop( 'additional_total', $context ); + } + + public function has_tracking() { + $has_tracking = true; + + if ( ! $this->has_tracking_instruction() && ! $this->get_tracking_url() ) { + $has_tracking = false; + } + + /** + * Check whether the label supports tracking or not + */ + if ( $this->has_label() && ( $label = $this->get_label() ) ) { + if ( ! $label->is_trackable() ) { + $has_tracking = false; + } + } + + return apply_filters( "{$this->get_general_hook_prefix()}has_tracking", $has_tracking, $this ); + } + + /** + * Returns the shipment tracking id. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_tracking_id( $context = 'view' ) { + return $this->get_prop( 'tracking_id', $context ); + } + + /** + * Returns the shipment tracking URL. + * + * @return string + */ + public function get_tracking_url() { + $tracking_url = ''; + + if ( $provider = $this->get_shipping_provider_instance() ) { + $tracking_url = $provider->get_tracking_url( $this ); + } + + /** + * Filter to adjust a Shipment's tracking URL. + * + * The dynamic portion of this hook, `$this->get_hook_prefix()` is used to construct a + * unique hook for a shipment type. + * + * Example hook name: woocommerce_gzd_shipment_get_tracking_url + * + * @param string $tracking_url The tracking URL. + * @param Shipment $shipment The shipment object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( "{$this->get_hook_prefix()}tracking_url", $tracking_url, $this ); + } + + /** + * Returns the shipment tracking instruction. + * + * @return string + */ + public function get_tracking_instruction( $plain = false ) { + $instruction = ''; + + if ( $provider = $this->get_shipping_provider_instance() ) { + $instruction = $provider->get_tracking_desc( $this, $plain ); + } + + /** + * Filter to adjust a Shipment's tracking instruction. + * + * The dynamic portion of this hook, `$this->get_hook_prefix()` is used to construct a + * unique hook for a shipment type. + * + * Example hook name: woocommerce_gzd_shipment_get_tracking_instruction + * + * @param string $instruction The tracking instruction. + * @param Shipment $this The shipment object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( "{$this->get_hook_prefix()}tracking_instruction", $instruction, $this ); + } + + /** + * Returns whether the current shipment has tracking instructions available or not. + * + * @return boolean + */ + public function has_tracking_instruction() { + $instruction = $this->get_tracking_instruction( true ); + + return ( ! empty( $instruction ) ) ? true : false; + } + + /** + * Returns the shipment shipping provider. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_shipping_provider( $context = 'view' ) { + return $this->get_prop( 'shipping_provider', $context ); + } + + public function get_shipping_provider_title() { + if ( $provider = $this->get_shipping_provider_instance() ) { + return $provider->get_title(); + } + + return ''; + } + + public function get_shipping_provider_instance() { + $provider = $this->get_shipping_provider(); + + if ( ! empty( $provider ) ) { + return wc_gzd_get_shipping_provider( $provider ); + } + + return false; + } + + /** + * Returns the formatted shipping address. + * + * @param string $empty_content Content to show if no address is present. + * @return string + */ + public function get_formatted_address( $empty_content = '' ) { + $address = WC()->countries->get_formatted_address( $this->get_address() ); + + return $address ? $address : $empty_content; + } + + /** + * Get a formatted shipping address for the order. + * + * @return string + */ + public function get_address_map_url( $address ) { + // Remove name and company before generate the Google Maps URL. + unset( $address['first_name'], $address['last_name'], $address['company'], $address['email'], $address['phone'], $address['title'] ); + + /** + * Filter to adjust a Shipment's address parts used for constructing the Google maps URL. + * + * The dynamic portion of this hook, `$this->get_hook_prefix()` is used to construct a + * unique hook for a shipment type. + * + * Example hook name: woocommerce_gzd_shipment_get_address_map_url_parts + * + * @param string[] $address The address parts used. + * @param Shipment $this The shipment object. + * + * @since 3.0.6 + * @package Vendidero/Germanized/Shipments + */ + $address = apply_filters( "{$this->get_hook_prefix()}address_map_url_parts", $address, $this ); + $address = array_filter( $address ); + + /** + * Filter to adjust a Shipment's address Google maps URL. + * + * The dynamic portion of this hook, `$this->get_hook_prefix()` is used to construct a + * unique hook for a shipment type. + * + * Example hook name: woocommerce_gzd_shipment_get_address_map_url + * + * @param string $url The address url. + * @param Shipment $this The shipment object. + * + * @since 3.0.6 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( "{$this->get_hook_prefix()}address_map_url", 'https://maps.google.com/maps?&q=' . rawurlencode( implode( ', ', $address ) ) . '&z=16', $this ); + } + + /** + * Returns the shipment address phone number. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_phone( $context = 'view' ) { + return $this->get_address_prop( 'phone', $context ); + } + + /** + * Returns the shipment address email. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_email( $context = 'view' ) { + return $this->get_address_prop( 'email', $context ); + } + + /** + * Returns the shipment address first line. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_address_1( $context = 'view' ) { + return $this->get_address_prop( 'address_1', $context ); + } + + /** + * Returns the shipment address second line. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_address_2( $context = 'view' ) { + return $this->get_address_prop( 'address_2', $context ); + } + + /** + * Returns the shipment address street number by splitting the address. + * + * @param string $type The address type e.g. address_1 or address_2. + * + * @return string + */ + public function get_address_street_number( $type = 'address_1' ) { + $split = wc_gzd_split_shipment_street( $this->{"get_$type"}() ); + + /** + * Filter to adjust the shipment address street number. + * + * @param string $number The shipment address street number. + * @param Shipment $shipment The shipment object. + * + * @since 3.0.6 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_get_shipment_address_street_number', $split['number'], $this ); + } + + /** + * Returns the shipment address street without number by splitting the address. + * + * @param string $type The address type e.g. address_1 or address_2. + * + * @return string + */ + public function get_address_street( $type = 'address_1' ) { + $split = wc_gzd_split_shipment_street( $this->{"get_$type"}() ); + + /** + * Filter to adjust the shipment address street. + * + * @param string $street The shipment address street without street number. + * @param Shipment $shipment The shipment object. + * + * @since 3.0.6 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_get_shipment_address_street', $split['street'], $this ); + } + + public function get_address_street_addition( $type = 'address_1' ) { + $split = wc_gzd_split_shipment_street( $this->{"get_$type"}() ); + + /** + * Filter to adjust the shipment address street addition. + * + * @param string $addition The shipment address street addition e.g. EG14. + * @param Shipment $shipment The shipment object. + * + * @since 3.0.6 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_get_shipment_address_street_addition', $split['addition'], $this ); + } + + public function get_address_street_addition_2( $type = 'address_1' ) { + $split = wc_gzd_split_shipment_street( $this->{"get_$type"}() ); + + /** + * Filter to adjust the shipment address street addition. + * + * @param string $addition The shipment address street addition e.g. EG14. + * @param Shipment $shipment The shipment object. + * + * @since 3.0.6 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_get_shipment_address_street_addition_2', $split['addition_2'], $this ); + } + + /** + * Returns the shipment address company. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_company( $context = 'view' ) { + return $this->get_address_prop( 'company', $context ); + } + + /** + * Returns the shipment address first name. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_first_name( $context = 'view' ) { + return $this->get_address_prop( 'first_name', $context ); + } + + /** + * Returns the shipment address last name. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_last_name( $context = 'view' ) { + return $this->get_address_prop( 'last_name', $context ); + } + + /** + * Returns the shipment address formatted full name. + * + * @return string + */ + public function get_formatted_full_name() { + return sprintf( _x( '%1$s %2$s', 'full name', 'woocommerce-germanized' ), $this->get_first_name(), $this->get_last_name() ); + } + + /** + * Returns the shipment address postcode. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_postcode( $context = 'view' ) { + return $this->get_address_prop( 'postcode', $context ); + } + + /** + * Returns the shipment address city. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_city( $context = 'view' ) { + return $this->get_address_prop( 'city', $context ); + } + + /** + * Returns the shipment address state. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_state( $context = 'view' ) { + return $this->get_address_prop( 'state', $context ); + } + + public function get_formatted_state() { + if ( '' === $this->get_state() || '' === $this->get_country() ) { + return ''; + } + + return wc_gzd_get_formatted_state( $this->get_state(), $this->get_country() ); + } + + /** + * Returns the shipment address country. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_country( $context = 'view' ) { + return $this->get_address_prop( 'country', $context ) ? $this->get_address_prop( 'country', $context ) : ''; + } + + /** + * Returns the shipment address customs reference number. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_customs_reference_number( $context = 'view' ) { + return $this->get_address_prop( 'customs_reference_number', $context ) ? $this->get_address_prop( 'customs_reference_number', $context ) : ''; + } + + /** + * Returns a sender address prop by checking the corresponding provider and falling back to + * global sender address setting data. + * + * @param string $prop + * @param string $context + * + * @return null|string + */ + protected function get_sender_address_prop( $prop, $context = 'view' ) { + $value = null; + + if ( $provider = $this->get_shipping_provider_instance() ) { + $getter = "get_shipper_{$prop}"; + + if ( is_callable( array( $provider, $getter ) ) ) { + $value = $provider->$getter( $context ); + } + } else { + $key = "woocommerce_gzd_shipments_shipper_address_{$prop}"; + $value = get_option( $key, '' ); + } + + if ( 'view' === $context ) { + /** + * Filter to adjust a shipment's sender address property e.g. first_name. + * + * The dynamic portion of this hook, `$this->get_hook_prefix()` is used to construct a + * unique hook for a shipment type. `$prop` refers to the actual address property e.g. first_name. + * + * Example hook name: woocommerce_gzd_shipment_get_sender_address_first_name + * + * @param string $value The address property value. + * @param Shipment $this The shipment object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + $value = apply_filters( "{$this->get_hook_prefix()}sender_address_{$prop}", $value, $this ); + } + + return $value; + } + + /** + * Returns the formatted sender address. + * + * @param string $empty_content Content to show if no address is present. + * @return string + */ + public function get_formatted_sender_address( $empty_content = '' ) { + $address = WC()->countries->get_formatted_address( $this->get_sender_address() ); + + return $address ? $address : $empty_content; + } + + /** + * Returns the address of the sender e.g. customer. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string[] + */ + public function get_sender_address( $context = 'view' ) { + return apply_filters( + "{$this->get_hook_prefix()}sender_address", + array( + 'company' => $this->get_sender_company( $context ), + 'first_name' => $this->get_sender_first_name( $context ), + 'last_name' => $this->get_sender_last_name( $context ), + 'address_1' => $this->get_sender_address_1( $context ), + 'address_2' => $this->get_sender_address_2( $context ), + 'postcode' => $this->get_sender_postcode( $context ), + 'city' => $this->get_sender_city( $context ), + 'country' => $this->get_sender_country( $context ), + 'state' => $this->get_sender_state( $context ), + ), + $this + ); + } + + /** + * Returns the sender address phone number. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_sender_phone( $context = 'view' ) { + return $this->get_sender_address_prop( 'phone', $context ); + } + + /** + * Returns the sender address email. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_sender_email( $context = 'view' ) { + return $this->get_sender_address_prop( 'email', $context ); + } + + /** + * Returns the sender address first line. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_sender_address_1( $context = 'view' ) { + return $this->get_sender_address_prop( 'address_1', $context ); + } + + /** + * Returns the sender address second line. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_sender_address_2( $context = 'view' ) { + return $this->get_sender_address_prop( 'address_2', $context ); + } + + /** + * Returns the sender address street number by splitting the address. + * + * @param string $type The address type e.g. address_1 or address_2. + * + * @return string + */ + public function get_sender_address_street_number( $type = 'address_1' ) { + $split = wc_gzd_split_shipment_street( $this->{"get_sender_$type"}() ); + + return $split['number']; + } + + /** + * Returns the sender address street without number by splitting the address. + * + * @param string $type The address type e.g. address_1 or address_2. + * + * @return string + */ + public function get_sender_address_street( $type = 'address_1' ) { + $split = wc_gzd_split_shipment_street( $this->{"get_sender_$type"}() ); + + return $split['street']; + } + + /** + * Returns the sender address street addition by splitting the address. + * + * @param string $type The address type e.g. address_1 or address_2. + * + * @return string + */ + public function get_sender_address_street_addition( $type = 'address_1' ) { + $split = wc_gzd_split_shipment_street( $this->{"get_sender_$type"}() ); + + return $split['addition']; + } + + public function get_sender_address_street_addition_2( $type = 'address_1' ) { + $split = wc_gzd_split_shipment_street( $this->{"get_sender_$type"}() ); + + return $split['addition_2']; + } + + /** + * Returns the sender address company. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_sender_company( $context = 'view' ) { + return $this->get_sender_address_prop( 'company', $context ); + } + + /** + * Returns the sender address first name. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_sender_first_name( $context = 'view' ) { + return $this->get_sender_address_prop( 'first_name', $context ); + } + + /** + * Returns the shipment address last name. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_sender_last_name( $context = 'view' ) { + return $this->get_sender_address_prop( 'last_name', $context ); + } + + /** + * Returns the sender address formatted full name. + * + * @return string + */ + public function get_formatted_sender_full_name() { + return sprintf( _x( '%1$s %2$s', 'full name', 'woocommerce-germanized' ), $this->get_sender_first_name(), $this->get_sender_last_name() ); + } + + /** + * Returns the sender address postcode. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_sender_postcode( $context = 'view' ) { + return $this->get_sender_address_prop( 'postcode', $context ); + } + + /** + * Returns the sender address city. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_sender_city( $context = 'view' ) { + return $this->get_sender_address_prop( 'city', $context ); + } + + /** + * Returns the sender address state. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_sender_state( $context = 'view' ) { + return $this->get_sender_address_prop( 'state', $context ); + } + + /** + * Returns the sender address customs reference number. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_sender_customs_reference_number( $context = 'view' ) { + return $this->get_sender_address_prop( 'customs_reference_number', $context ) ? $this->get_sender_address_prop( 'customs_reference_number', $context ) : ''; + } + + public function get_formatted_sender_state() { + if ( '' === $this->get_sender_state() || '' === $this->get_sender_country() ) { + return ''; + } + + return wc_gzd_get_formatted_state( $this->get_sender_state(), $this->get_sender_country() ); + } + + /** + * Returns the sender address country. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_sender_country( $context = 'view' ) { + return $this->get_sender_address_prop( 'country', $context ) ? $this->get_sender_address_prop( 'country', $context ) : ''; + } + + /** + * Return the date this shipment is estimated to be delivered. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return WC_DateTime|null object if the date is set or null if there is no date. + */ + public function get_est_delivery_date( $context = 'view' ) { + return $this->get_prop( 'est_delivery_date', $context ); + } + + /** + * Decides whether the shipment is sent to an external pickup or not. + * + * @param string[]|string $types + * + * @return boolean + */ + public function send_to_external_pickup( $types ) { + $types = is_array( $types ) ? $types : array( $types ); + + /** + * Filter to decide whether a Shipment is to be sent to a external pickup location + * e.g. packstation. + * + * @param boolean $external True if the Shipment goes to a pickup location. + * @param array $types Array containing the types to be checked agains. + * @param Shipment $this The shipment object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipment_send_to_external_pickup', false, $types, $this ); + } + + /** + * Returns an address prop. + * + * @param string $prop + * @param string $context + * + * @return null|string + */ + protected function get_address_prop( $prop, $context = 'view' ) { + $value = null; + + if ( isset( $this->changes['address'][ $prop ] ) || isset( $this->data['address'][ $prop ] ) ) { + $value = isset( $this->changes['address'][ $prop ] ) ? $this->changes['address'][ $prop ] : $this->data['address'][ $prop ]; + + if ( 'view' === $context ) { + /** + * Filter to adjust a Shipment's shipping address property e.g. first_name. + * + * The dynamic portion of this hook, `$this->get_hook_prefix()` is used to construct a + * unique hook for a shipment type. `$prop` refers to the actual address property e.g. first_name. + * + * Example hook name: woocommerce_gzd_shipment_get_address_first_name + * + * @param string $value The address property value. + * @param Shipment $this The shipment object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + $value = apply_filters( "{$this->get_hook_prefix()}address_{$prop}", $value, $this ); + } + } + + return $value; + } + + /** + * Returns dimensions. + * + * @return string|array + */ + public function get_dimensions( $context = 'view' ) { + return array( + 'length' => $this->get_length( $context ), + 'width' => $this->get_width( $context ), + 'height' => $this->get_height( $context ), + ); + } + + /** + * Returns dimensions. + * + * @return string|array + */ + public function get_package_dimensions() { + return array( + 'length' => $this->get_package_length(), + 'width' => $this->get_package_width(), + 'height' => $this->get_package_height(), + ); + } + + public function get_formatted_dimensions() { + return wc_gzd_format_shipment_dimensions( $this->get_dimensions(), $this->get_dimension_unit() ); + } + + /** + * Returns whether the shipment is editable or not. + * + * @return boolean + */ + public function is_editable() { + /** + * Filter to dedice whether the current Shipment is still editable or not. + * + * @param boolean $is_editable Whether the Shipment is editable or not. + * @param Shipment $this The shipment object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipment_is_editable', $this->has_status( wc_gzd_get_shipment_editable_statuses() ), $this ); + } + + /** + * Returns the shipment number. + * + * @return string + */ + public function get_shipment_number() { + /** + * Filter to adjust a Shipment's number. + * + * The dynamic portion of this hook, `$this->get_hook_prefix()` is used to construct a + * unique hook for a shipment type. + * + * Example hook name: woocommerce_gzd_shipment_get_shipment_number + * + * @param string $number The shipment number. + * @param Shipment $this The shipment object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return (string) apply_filters( "{$this->get_hook_prefix()}shipment_number", $this->get_id(), $this ); + } + + /* + |-------------------------------------------------------------------------- + | Setters + |-------------------------------------------------------------------------- + */ + + /** + * Set shipment status. + * + * @param string $new_status Status to change the shipment to. No internal gzd- prefix is required. + * @param boolean $manual_update Whether it is a manual status update or not. + * @return array details of change + */ + public function set_status( $new_status, $manual_update = false ) { + $old_status = $this->get_status(); + $new_status = 'gzd-' === substr( $new_status, 0, 4 ) ? substr( $new_status, 4 ) : $new_status; + + $this->set_prop( 'status', $new_status ); + + $result = array( + 'from' => $old_status, + 'to' => $new_status, + ); + + if ( true === $this->object_read && ! empty( $result['from'] ) && $result['from'] !== $result['to'] ) { + $this->status_transition = array( + 'from' => ! empty( $this->status_transition['from'] ) ? $this->status_transition['from'] : $result['from'], + 'to' => $result['to'], + 'manual' => (bool) $manual_update, + ); + + if ( $manual_update ) { + /** + * Action that fires after a shipment status has been updated manually. + * + * @param integer $shipment_id The shipment id. + * @param string $status The new shipment status. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_shipment_edit_status', $this->get_id(), $result['to'] ); + } + + $this->maybe_set_date_sent(); + } + + return $result; + } + + public function is_shipped() { + $is_shipped = $this->has_status( wc_gzd_get_shipment_sent_statuses() ); + + return apply_filters( $this->get_hook_prefix() . 'is_shipped', $is_shipped, $this ); + } + + /** + * Maybe set date sent. + * + * Sets the date sent variable when transitioning to the shipped shipment status. + * Date sent is set once in this manner - only when it is not already set. + */ + public function maybe_set_date_sent() { + // This logic only runs if the date_sent prop has not been set yet. + if ( ! $this->get_date_sent( 'edit' ) ) { + if ( $this->is_shipped() ) { + // If payment complete status is reached, set paid now. + $this->set_date_sent( time() ); + } + } + } + + /** + * Updates status of shipment immediately. + * + * @uses Shipment::set_status() + * + * @param string $new_status Status to change the shipment to. No internal gzd- prefix is required. + * @param bool $manual Is this a manual order status change? + * @return bool + */ + public function update_status( $new_status, $manual = false ) { + if ( ! $this->get_id() ) { + return false; + } + + try { + $this->set_status( $new_status, $manual ); + $this->save(); + } catch ( Exception $e ) { + $logger = wc_get_logger(); + $logger->error( + sprintf( 'Error updating status for shipment #%d', $this->get_id() ), + array( + 'shipment' => $this, + 'error' => $e, + ) + ); + return false; + } + return true; + } + + /** + * Set the date this shipment was created. + * + * @param string|integer|null $date UTC timestamp, or ISO 8601 DateTime. If the DateTime string has no timezone or offset, WordPress site timezone will be assumed. Null if their is no date. + */ + public function set_date_created( $date = null ) { + $this->set_date_prop( 'date_created', $date ); + } + + /** + * Set the date this shipment was sent. + * + * @param string|integer|null $date UTC timestamp, or ISO 8601 DateTime. If the DateTime string has no timezone or offset, WordPress site timezone will be assumed. Null if their is no date. + */ + public function set_date_sent( $date = null ) { + $this->set_date_prop( 'date_sent', $date ); + } + + /** + * Set shipment weight in kg. + * + * @param string $weight The weight. + */ + public function set_weight( $weight ) { + $this->set_prop( 'weight', '' === $weight ? '' : wc_format_decimal( $weight ) ); + } + + public function set_packaging_weight( $weight ) { + $this->set_prop( 'packaging_weight', '' === $weight ? '' : wc_format_decimal( $weight ) ); + } + + /** + * Set shipment total weight. + * + * @param string $weight The weight. + */ + public function set_total_weight( $weight ) { + $this->set_prop( 'total_weight', '' === $weight ? '' : wc_format_decimal( $weight ) ); + } + + /** + * Set shipment width. + * + * @param string $width The width. + */ + public function set_width( $width ) { + $this->set_prop( 'width', '' === $width ? '' : wc_format_decimal( $width ) ); + } + + public function set_weight_unit( $unit ) { + $this->set_prop( 'weight_unit', $unit ); + } + + public function set_dimension_unit( $unit ) { + $this->set_prop( 'dimension_unit', $unit ); + } + + /** + * Set shipment length. + * + * @param string $length The length. + */ + public function set_length( $length ) { + $this->set_prop( 'length', '' === $length ? '' : wc_format_decimal( $length ) ); + } + + /** + * Set shipment height. + * + * @param string $height The height. + */ + public function set_height( $height ) { + $this->set_prop( 'height', '' === $height ? '' : wc_format_decimal( $height ) ); + } + + /** + * Set shipment address. + * + * @param string[] $address The address props. + */ + public function set_address( $address ) { + $this->set_prop( 'address', empty( $address ) ? array() : (array) $address ); + } + + /** + * Set shipment shipping method. + * + * @param string $method The shipping method. + */ + public function set_shipping_method( $method ) { + $this->shipping_method_instance = null; + + $this->set_prop( 'shipping_method', $method ); + } + + /** + * Set shipment version. + * + * @param string $version The version. + */ + public function set_version( $version ) { + $this->set_prop( 'version', $version ); + } + + /** + * Set the date this shipment will be delivered. + * + * @param string|integer|null $date UTC timestamp, or ISO 8601 DateTime. If the DateTime string has no timezone or offset, WordPress site timezone will be assumed. Null if their is no date. + */ + public function set_est_delivery_date( $date = null ) { + $this->set_date_prop( 'est_delivery_date', $date ); + } + + /** + * Set shipment total. + * + * @param float|string $value The shipment total. + */ + public function set_total( $value ) { + $value = wc_format_decimal( $value ); + + if ( ! is_numeric( $value ) ) { + $value = 0; + } + + $this->set_prop( 'total', $value ); + } + + /** + * Set shipment total. + * + * @param float|string $value The shipment total. + */ + public function set_subtotal( $value ) { + $value = wc_format_decimal( $value ); + + if ( ! is_numeric( $value ) ) { + $value = 0; + } + + $this->set_prop( 'subtotal', $value ); + } + + /** + * Set shipment additional total. + * + * @param float|string $value The shipment total. + */ + public function set_additional_total( $value ) { + $value = wc_format_decimal( $value ); + + if ( ! is_numeric( $value ) ) { + $value = 0; + } + + $this->set_prop( 'additional_total', $value ); + } + + /** + * Set shipment shipping country. + * + * @param string $country The country in ISO format. + */ + public function set_country( $country ) { + $this->set_address_prop( 'country', $country ); + } + + /** + * Update a specific address prop. + * + * @param $prop + * @param $value + */ + protected function set_address_prop( $prop, $value ) { + $address = $this->get_address(); + $address[ $prop ] = $value; + + $this->set_address( $address ); + } + + /** + * Set shipment tracking id. + * + * @param string $tracking_id The trakcing id. + */ + public function set_tracking_id( $tracking_id ) { + $this->set_prop( 'tracking_id', $tracking_id ); + } + + /** + * Set shipment shipping provider. + * + * @param string $provider The shipping provider. + */ + public function set_shipping_provider( $provider ) { + $this->set_prop( 'shipping_provider', wc_gzd_get_shipping_provider_slug( $provider ) ); + } + + /** + * Set packaging id. + * + * @param integer $packaging_id The packaging id. + */ + public function set_packaging_id( $packaging_id ) { + $this->set_prop( 'packaging_id', absint( $packaging_id ) ); + + $this->packaging = null; + } + + public function sync_packaging() { + $available_packaging = $this->get_available_packaging(); + $default_packaging = $this->get_default_packaging(); + $packaging_id = $this->get_packaging_id( 'edit' ); + + if ( ! empty( $packaging_id ) ) { + $exists = false; + + foreach ( $available_packaging as $packaging ) { + if ( (int) $packaging_id === (int) $packaging->get_id() ) { + $exists = true; + break; + } + } + + if ( ! $exists && $default_packaging ) { + $this->set_packaging_id( $default_packaging->get_id() ); + } + } elseif ( empty( $packaging_id ) && $default_packaging ) { + $this->set_packaging_id( $default_packaging->get_id() ); + } + } + + public function update_packaging() { + if ( $packaging = $this->get_packaging() ) { + $packaging_dimension = wc_gzd_get_packaging_dimension_unit(); + + $props = array( + 'width' => wc_get_dimension( $packaging->get_width( 'edit' ), $this->get_dimension_unit(), $packaging_dimension ), + 'length' => wc_get_dimension( $packaging->get_length( 'edit' ), $this->get_dimension_unit(), $packaging_dimension ), + 'height' => wc_get_dimension( $packaging->get_height( 'edit' ), $this->get_dimension_unit(), $packaging_dimension ), + 'packaging_weight' => wc_get_weight( $packaging->get_weight( 'edit' ), $this->get_weight_unit(), wc_gzd_get_packaging_weight_unit() ), + ); + + $this->set_props( $props ); + } else { + $props = array( 'packaging_weight' => '' ); + $changes = $this->get_changes(); + + /** + * Maybe reset dimensions in case they've not been explicitly set + */ + if ( array_key_exists( 'packaging_id', $changes ) ) { + foreach ( array( 'length', 'width', 'height' ) as $dim_prop ) { + if ( ! array_key_exists( $dim_prop, $changes ) ) { + $props = array_merge( $props, array( $dim_prop => '' ) ); + } + } + } + + // Reset + $this->set_props( $props ); + } + + return true; + } + + /** + * Return an array of items within this shipment. + * + * @return ShipmentItem[] + */ + public function get_items() { + $items = array(); + + if ( is_null( $this->items ) ) { + $this->items = array_filter( $this->data_store->read_items( $this ) ); + + $items = (array) $this->items; + } else { + $items = (array) $this->items; + } + + /** + * Filter to adjust items belonging to a Shipment. + * + * The dynamic portion of this hook, `$this->get_hook_prefix()` is used to construct a + * unique hook for a shipment type. + * + * Example hook name: woocommerce_gzd_shipment_get_items + * + * @param string $number The shipment number. + * @param Shipment $this The shipment object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( "{$this->get_hook_prefix()}items", $items, $this ); + } + + /** + * Get's the URL to edit the shipment in the backend. + * + * @return string + */ + abstract public function get_edit_shipment_url(); + + public function get_view_shipment_url() { + /** + * Filter to adjust the URL being used to access the view shipment page on the customer account page. + * + * The dynamic portion of this hook, `$this->get_hook_prefix()` is used to construct a + * unique hook for a shipment type. + * + * Example hook name: woocommerce_gzd_shipment_view_shipment_url + * + * @param string $url The URL pointing to the view page. + * @param Shipment $this The shipment object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( "{$this->get_hook_prefix()}_view_shipment_url", wc_get_endpoint_url( 'view-shipment', $this->get_id(), wc_get_page_permalink( 'myaccount' ) ), $this ); + } + + /** + * Get an item object. + * + * @param int $item_id ID of item to get. + * + * @return ShipmentItem|false + */ + public function get_item( $item_id ) { + $items = $this->get_items(); + + if ( isset( $items[ $item_id ] ) ) { + return $items[ $item_id ]; + } + + return false; + } + + /** + * Remove item from the shipment. + * + * @param int $item_id Item ID to delete. + * + * @return false|void + */ + public function remove_item( $item_id ) { + $item = $this->get_item( $item_id ); + + // Unset and remove later. + $this->items_to_delete[] = $item; + + unset( $this->items[ $item->get_id() ] ); + + $this->reset_content_data(); + $this->calculate_totals(); + $this->sync_packaging(); + } + + public function update_item_quantity( $item_id, $quantity = 1 ) { + if ( $item = $this->get_item( $item_id ) ) { + $item->set_quantity( $quantity ); + + if ( array_key_exists( 'quantity', $item->get_changes() ) ) { + $this->sync_packaging(); + } + + return true; + } + + return false; + } + + /** + * Adds a shipment item to this shipment. The shipment item will not persist until save. + * + * @since 3.0.0 + * @param ShipmentItem $item Shipment item object. + * + * @return false|void + */ + public function add_item( $item ) { + // Make sure that items are loaded + $items = $this->get_items(); + + // Set parent. + $item->set_shipment_id( $this->get_id() ); + + // Append new row with generated temporary ID. + $item_id = $item->get_id(); + + if ( $item_id ) { + $this->items[ $item_id ] = $item; + } else { + $this->items[ 'new:' . count( $this->items ) ] = $item; + } + + $this->items_to_pack = null; + + $this->reset_content_data(); + $this->calculate_totals(); + $this->sync_packaging(); + } + + /** + * Reset item content data. + */ + protected function reset_content_data() { + $this->weights = null; + $this->lengths = null; + $this->widths = null; + $this->heights = null; + $this->volumes = null; + } + + /** + * Handle the status transition. + */ + protected function status_transition() { + $status_transition = $this->status_transition; + + // Reset status transition variable. + $this->status_transition = false; + + if ( $status_transition ) { + try { + /** + * Action that fires before a shipment status transition happens. + * + * @param integer $shipment_id The shipment id. + * @param Shipment $shipment The shipment object. + * @param array $status_transition The status transition data. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_shipment_before_status_change', $this->get_id(), $this, $this->status_transition ); + + $status_to = $status_transition['to']; + $status_hook_prefix = 'woocommerce_gzd_' . ( 'simple' === $this->get_type() ? '' : $this->get_type() . '_' ) . 'shipment_status'; + + /** + * Action that indicates shipment status change to a specific status. + * + * The dynamic portion of the hook name, `$status_hook_prefix` constructs a unique prefix + * based on the shipment type. `$status_to` refers to the new shipment status. + * + * Example hook name: `woocommerce_gzd_return_shipment_status_processing` + * + * @param integer $shipment_id The shipment id. + * @param Shipment $shipment The shipment object. + * + * @see wc_gzd_get_shipment_statuses() + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( "{$status_hook_prefix}_$status_to", $this->get_id(), $this ); + + if ( ! empty( $status_transition['from'] ) ) { + $status_from = $status_transition['from']; + + /** + * Action that indicates shipment status change from a specific status to a specific status. + * + * The dynamic portion of the hook name, `$status_hook_prefix` constructs a unique prefix + * based on the shipment type. `$status_from` refers to the old shipment status. + * `$status_to` refers to the new status. + * + * Example hook name: `woocommerce_gzd_return_shipment_status_processing_to_shipped` + * + * @param integer $shipment_id The shipment id. + * @param Shipment $shipment The shipment object. + * + * @see wc_gzd_get_shipment_statuses() + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( "{$status_hook_prefix}_{$status_from}_to_{$status_to}", $this->get_id(), $this ); + + /** + * Action that indicates shipment status change. + * + * @param integer $shipment_id The shipment id. + * @param string $status_from The old shipment status. + * @param string $status_to The new shipment status. + * @param Shipment $shipment The shipment object. + * + * @see wc_gzd_get_shipment_statuses() + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_shipment_status_changed', $this->get_id(), $status_from, $status_to, $this ); + } + } catch ( Exception $e ) { + $logger = wc_get_logger(); + $logger->error( + sprintf( 'Status transition of shipment #%d errored!', $this->get_id() ), + array( + 'shipment' => $this, + 'error' => $e, + ) + ); + } + } + } + + /** + * Remove all items from the shipment. + */ + public function remove_items() { + $this->data_store->delete_items( $this ); + $this->items = array(); + + $this->items_to_pack = null; + + $this->reset_content_data(); + $this->calculate_totals(); + $this->sync_packaging(); + } + + /** + * Save all items which are part of this shipment. + */ + protected function save_items() { + $items_changed = false; + + foreach ( $this->items_to_delete as $item ) { + $item->delete(); + $items_changed = true; + } + + $this->items_to_delete = array(); + + foreach ( $this->get_items() as $item_key => $item ) { + $item->set_shipment_id( $this->get_id() ); + + $item_id = $item->save(); + + // If ID changed (new item saved to DB)... + if ( $item_id !== $item_key ) { + $this->items[ $item_id ] = $item; + + unset( $this->items[ $item_key ] ); + + $items_changed = true; + } + } + } + + /** + * Finds an ShipmentItem based on an order item id. + * + * @param integer $order_item_id + * + * @return bool|ShipmentItem + */ + public function get_item_by_order_item_id( $order_item_id ) { + $items = $this->get_items(); + + foreach ( $items as $item ) { + if ( $item->get_order_item_id() === (int) $order_item_id ) { + return $item; + } + } + + return false; + } + + /** + * Returns version. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return integer + */ + public function get_version( $context = 'view' ) { + return $this->get_prop( 'version', $context ); + } + + /** + * Returns the packaging id belonging to the shipment. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return integer + */ + public function get_packaging_id( $context = 'view' ) { + return $this->get_prop( 'packaging_id', $context ); + } + + public function get_packaging() { + if ( is_null( $this->packaging ) && $this->get_packaging_id() > 0 ) { + if ( $packaging = wc_gzd_get_packaging( $this->get_packaging_id() ) ) { + // Do only allow load packaging if it does really exist in DB. + if ( $packaging->get_id() > 0 ) { + $this->packaging = $packaging; + } + } + } + + return $this->packaging; + } + + public function get_available_packaging() { + $packaging_store = \WC_Data_Store::load( 'packaging' ); + + return apply_filters( "{$this->get_hook_prefix()}available_packaging", $packaging_store->find_available_packaging_for_shipment( $this ), $this ); + } + + public function get_default_packaging() { + $packaging_store = \WC_Data_Store::load( 'packaging' ); + $default_packaging = $packaging_store->find_best_match_for_shipment( $this ); + + if ( ! $default_packaging ) { + $setting = Package::get_setting( 'default_packaging' ); + + if ( ! empty( $setting ) && wc_gzd_get_packaging( $setting ) ) { + $default_packaging = wc_gzd_get_packaging( $setting ); + } + } + + return apply_filters( "{$this->get_hook_prefix()}default_packaging_id", $default_packaging, $this ); + } + + /** + * Tries to fetch the order for the current shipment. + * + * @return bool|WC_Order|null + */ + abstract public function get_order(); + + abstract public function get_order_id(); + + /** + * Returns the formatted order number. + * + * @return string + */ + public function get_order_number() { + if ( $order = $this->get_order() ) { + return $order->get_order_number(); + } + + return $this->get_order_id(); + } + + /** + * Returns whether the Shipment contains an order item or not. + * + * @param integer|integer[] $item_id + * + * @return boolean + */ + public function contains_order_item( $item_id ) { + + if ( ! is_array( $item_id ) ) { + $item_id = array( $item_id ); + } + + $new_items = $item_id; + + foreach ( $item_id as $key => $order_item_id ) { + + if ( is_a( $order_item_id, 'WC_Order_Item' ) ) { + $order_item_id = $order_item_id->get_id(); + $item_id[ $key ] = $order_item_id; + } + + if ( $this->get_item_by_order_item_id( $order_item_id ) ) { + unset( $new_items[ $key ] ); + } + } + + $contains = empty( $new_items ) ? true : false; + + /** + * Filter to adjust whether a Shipment contains a specific order item or not. + * + * @param boolean $contains Whether the Shipment contains the order item or not. + * @param integer[] $order_item_id The order item id(s). + * @param Shipment $this The shipment object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipment_contains_order_item', $contains, $item_id, $this ); + } + + public function get_shippable_item_count() { + return 0; + } + + /** + * Finds an ShipmentItem based on an item parent id. + * + * @param integer $item_parent_id + * + * @return bool|ShipmentItem + */ + public function get_item_by_item_parent_id( $item_parent_id ) { + $items = $this->get_items(); + + foreach ( $items as $item ) { + if ( $item->get_parent_id() === $item_parent_id ) { + return $item; + } + } + + return false; + } + + public function needs_items( $available_items = false ) { + return false; + } + + public function sync( $args = array() ) { + return false; + } + + public function sync_items( $args = array() ) { + return false; + } + + /** + * Returns a label + * + * @return boolean|ShipmentLabel|ShipmentReturnLabel + */ + public function get_label() { + $label = false; + $prefix = ''; + + if ( $provider = $this->get_shipping_provider_instance() ) { + $prefix = $provider->get_name() . '_'; + $label = $provider->get_label( $this ); + } + + /** + * Filter for shipping providers to retrieve the `ShipmentLabel` corresponding to a certain shipment. + * + * The dynamic portion of this hook, `$this->get_hook_prefix()` is used to construct a + * unique hook for a shipment type. `$provider` is related to the current shipping provider + * for the shipment (slug). + * + * Example hook name: `woocommerce_gzd_return_shipment_get_dhl_label` + * + * @param boolean|ShipmentLabel $label The label instance. + * @param Shipment $shipment The current shipment instance. + * + * @since 3.0.6 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( "{$this->get_hook_prefix()}{$prefix}label", $label, $this ); + } + + /** + * Output label admin fields. + */ + public function get_label_settings_html() { + $hook_prefix = $this->get_general_hook_prefix(); + $html = ''; + + if ( $provider = $this->get_shipping_provider_instance() ) { + $hook_prefix = $hook_prefix . '_' . $provider->get_name(); + $html = $provider->get_label_fields_html( $this ); + } + + /** + * Action for shipping providers to output available admin settings while creating a label. + * + * The dynamic portion of this hook, `$hook_prefix` is used to construct a + * unique hook for a shipment type. `$provider` is related to the current shipping provider + * for the shipment (slug). + * + * Example hook name: `woocommerce_gzd_return_shipment_print_dhl_label_admin_fields` + * + * @param Shipment $shipment The current shipment instance. + * + * @since 3.0.6 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( "{$hook_prefix}label_settings_html", $html, $this ); + } + + public function create_label( $props = false ) { + $hook_prefix = $this->get_general_hook_prefix(); + $provider_name = ''; + $error = new WP_Error(); + + /** + * Sanitize props + */ + if ( is_array( $props ) ) { + foreach ( $props as $key => $value ) { + $props[ $key ] = wc_clean( wp_unslash( $value ) ); + } + } + + if ( $provider = $this->get_shipping_provider_instance() ) { + $provider_name = $provider->get_name(); + $result = $provider->create_label( $this, $props ); + + if ( is_wp_error( $result ) ) { + return $result; + } + } else { + /** + * Action for shipping providers to create the `ShipmentLabel` corresponding to a certain shipment. + * + * The dynamic portion of this hook, `$hook_prefix` is used to construct a + * unique hook for a shipment type. `$provider` is related to the current shipping provider + * for the shipment (slug). + * + * Example hook name: `woocommerce_gzd_return_shipment_create_dhl_label` + * + * @param array|false $props Array containing props extracted from post data (if created manually). + * @param WP_Error $error An WP_Error instance useful for returning errors while creating the label. + * @param Shipment $shipment The current shipment instance. + * + * @since 3.0.6 + * @package Vendidero/Germanized/Shipments + */ + do_action( "{$hook_prefix}create_{$provider_name}label", $props, $error, $this ); + + if ( wc_gzd_shipment_wp_error_has_errors( $error ) ) { + return $error; + } + } + + if ( $label = $this->get_label() ) { + $this->set_tracking_id( $label->get_number() ); + + /** + * Action for shipping providers to adjust the shipment before updating it after a label has + * been successfully generated. + * + * The dynamic portion of this hook, `$hook_prefix` is used to construct a + * unique hook for a shipment type. `$provider` is related to the current shipping provider + * for the shipment (slug). + * + * Example hook name: `woocommerce_gzd_return_shipment_created_dhl_label` + * + * @param Shipment $shipment The current shipment instance. + * @param array $props Array containing props extracted from post data (if created manually) and sanitized via `wc_clean`. + * @param array $raw_data Raw post data unsanitized. + * + * @since 3.1.2 + * @package Vendidero/Germanized/Shipments + */ + do_action( "{$hook_prefix}created_{$provider_name}label", $this, $props ); + + do_action( "{$hook_prefix}created_label", $this, $props ); + + $this->save(); + } + + return true; + } + + public function delete_label( $force = false ) { + if ( $this->supports_label() && ( $label = $this->get_label() ) ) { + $label->delete( $force ); + $this->set_tracking_id( '' ); + $this->save(); + + return true; + } + + return false; + } + + /** + * Whether or not the current shipments supports labels or not. + * + * @return bool + */ + public function supports_label() { + if ( $provider = $this->get_shipping_provider_instance() ) { + if ( $provider->supports_labels( $this->get_type(), $this ) ) { + return true; + } + } + + return false; + } + + /** + * Whether or not the current shipments needs a label or not. + * + * @return bool + */ + public function needs_label( $check_status = true ) { + $needs_label = true; + $provider = $this->get_shipping_provider(); + $hook_prefix = $this->get_general_hook_prefix(); + + if ( ! empty( $provider ) ) { + $provider = $provider . '_'; + } + + if ( $this->has_label() ) { + $needs_label = false; + } + + if ( ! $this->supports_label() ) { + $needs_label = false; + } + + if ( $shipping_provider = $this->get_shipping_provider_instance() ) { + if ( ! $shipping_provider->is_activated() ) { + $needs_label = false; + } + } + + // If shipment is already delivered + if ( $check_status && $this->is_shipped() ) { + $needs_label = false; + } + + /** + * Filter for shipping providers to decide whether the shipment needs a label or not. + * + * The dynamic portion of this hook, `$hook_prefix` is used to construct a + * unique hook for a shipment type. `$provider` is related to the current shipping provider + * for the shipment (slug). + * + * Example hook name: `woocommerce_gzd_return_shipment_needs_dhl_label` + * + * @param boolean $needs_label Whether or not the shipment needs a label. + * @param boolean $check_status Whether or not checking the shipment status is needed. + * @param Shipment $shipment The current shipment instance. + * + * @since 3.0.6 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( "{$hook_prefix}needs_{$provider}label", $needs_label, $check_status, $this ); + } + + /** + * Whether or not the current shipment has a valid label or not. + * + * @return bool + */ + public function has_label() { + $label = $this->get_label(); + + if ( $label && is_a( $label, '\Vendidero\Germanized\Shipments\Interfaces\ShipmentLabel' ) ) { + if ( 'return' === $label->get_type() ) { + if ( ! is_a( $label, '\Vendidero\Germanized\Shipments\Interfaces\ShipmentReturnLabel' ) ) { + return false; + } + } + + return true; + } else { + return false; + } + } + + public function get_label_download_url( $args = array() ) { + $download_url = ''; + $provider = $this->get_shipping_provider(); + + if ( $label = $this->get_label() ) { + $download_url = $label->get_download_url( $args ); + } + + /** + * Filter for shipping providers to adjust the label download URL. + * + * The dynamic portion of this hook, `$this->get_hook_prefix()` is used to construct a + * unique hook for a shipment type. `$provider` is related to the current shipping provider + * for the shipment (slug). + * + * Example hook name: `woocommerce_gzd_return_shipment_get_dhl_label_download_url` + * + * @param string $url The download URL. + * @param Shipment $shipment The current shipment instance. + * + * @since 3.0.6 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( "{$this->get_hook_prefix()}{$provider}label_download_url", $download_url, $this ); + } + + public function add_note( $note, $added_by_user = false ) { + if ( $order = $this->get_order() ) { + if ( is_callable( array( $order, 'add_order_note' ) ) ) { + $order->add_order_note( $note, 0, $added_by_user ); + } + } + } + + /** + * Calculate totals based on contained items. + */ + protected function calculate_totals() { + $total = 0; + $subtotal = 0; + + foreach ( $this->get_items() as $item ) { + $total += round( $item->get_total(), wc_get_price_decimals() ); + $subtotal += round( $item->get_subtotal(), wc_get_price_decimals() ); + } + + $this->set_total( $total ); + + if ( empty( $subtotal ) ) { + $subtotal = $total; + } + + $this->set_subtotal( $subtotal ); + } + + public function delete( $force_delete = false ) { + $this->delete_label( $force_delete ); + + return parent::delete( $force_delete ); + } + + /** + * Save data to the database. + * + * @return integer shipment id + */ + public function save() { + try { + $this->calculate_totals(); + $is_new = false; + + if ( array_key_exists( 'packaging_id', $this->get_changes() ) || $this->is_editable() ) { + $this->update_packaging(); + } + + if ( $this->data_store ) { + // Trigger action before saving to the DB. Allows you to adjust object props before save. + do_action( 'woocommerce_before_' . $this->object_type . '_object_save', $this, $this->data_store ); + + if ( $this->get_id() ) { + $this->data_store->update( $this ); + } else { + $this->data_store->create( $this ); + $is_new = true; + } + } + + $this->save_items(); + + /** + * Trigger action after saving shipment to the DB. + * + * @param Shipment $shipment The shipment object being saved. + * @param WC_Data_Store_WP $data_store THe data store persisting the data. + */ + do_action( 'woocommerce_after_' . $this->object_type . '_object_save', $this, $this->data_store ); + + $hook_postfix = ''; + + if ( 'simple' !== $this->get_type() ) { + $hook_postfix = $this->get_type() . '_'; + } + + /** + * Trigger action after saving shipment to the DB. + * + * The dynamic portion of this hook, `$hook_postfix` is used to construct a + * unique hook for a shipment type. + * + * Example hook name: woocommerce_gzd_shipment_after_save + * + * @param Shipment $shipment The shipment object being saved. + * @param boolean $is_new Indicator to determine whether this is a new shipment or not. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( "woocommerce_gzd_{$hook_postfix}shipment_after_save", $this, $is_new ); + + $this->status_transition(); + $this->reset_content_data(); + + } catch ( Exception $e ) { + $logger = wc_get_logger(); + $logger->error( + sprintf( 'Error saving shipment #%d', $this->get_id() ), + array( + 'shipment' => $this, + 'error' => $e, + ) + ); + } + + return $this->get_id(); + } +} diff --git a/packages/woocommerce-germanized-shipments/src/ShipmentFactory.php b/packages/woocommerce-germanized-shipments/src/ShipmentFactory.php new file mode 100644 index 000000000..f6595c8e9 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/ShipmentFactory.php @@ -0,0 +1,88 @@ +get_shipment_type( $shipment_id ); + + /** + * Shipment type cannot be found, seems to not exist. + */ + if ( empty( $shipment_type ) ) { + return false; + } + + $shipment_type_data = wc_gzd_get_shipment_type_data( $shipment_type ); + } else { + $shipment_type_data = wc_gzd_get_shipment_type_data( $shipment_type ); + } + + if ( $shipment_type_data ) { + $classname = $shipment_type_data['class_name']; + } else { + $classname = false; + } + + /** + * Filter to adjust the classname used to construct a Shipment. + * + * @param string $clasname The classname to be used. + * @param integer $shipment_id The shipment id. + * @param string $shipment_type The shipment type. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + $classname = apply_filters( 'woocommerce_gzd_shipment_class', $classname, $shipment_id, $shipment_type ); + + if ( ! class_exists( $classname ) ) { + return false; + } + + try { + return new $classname( $shipment_id ); + } catch ( Exception $e ) { + wc_caught_exception( $e, __FUNCTION__, array( $shipment_id, $shipment_type ) ); + return false; + } + } + + public static function get_shipment_id( $shipment ) { + if ( is_numeric( $shipment ) ) { + return $shipment; + } elseif ( $shipment instanceof Shipment ) { + return $shipment->get_id(); + } elseif ( ! empty( $shipment->shipment_id ) ) { + return $shipment->shipment_id; + } else { + return false; + } + } +} diff --git a/packages/woocommerce-germanized-shipments/src/ShipmentItem.php b/packages/woocommerce-germanized-shipments/src/ShipmentItem.php new file mode 100644 index 000000000..4b3fe3de3 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/ShipmentItem.php @@ -0,0 +1,605 @@ + 0, + 'order_item_id' => 0, + 'parent_id' => 0, + 'quantity' => 1, + 'product_id' => 0, + 'weight' => '', + 'width' => '', + 'length' => '', + 'height' => '', + 'sku' => '', + 'name' => '', + 'total' => 0, + 'subtotal' => 0, + 'hs_code' => '', + 'manufacture_country' => '', + 'attributes' => array(), + ); + + /** + * Stores meta in cache for future reads. + * A group must be set to to enable caching. + * + * @var string + */ + protected $cache_group = 'shipment-items'; + + /** + * Meta type. This should match up with + * the types available at https://developer.wordpress.org/reference/functions/add_metadata/. + * WP defines 'post', 'user', 'comment', and 'term'. + * + * @var string + */ + protected $meta_type = 'shipment_item'; + + /** + * This is the name of this object type. + * + * @var string + */ + protected $object_type = 'shipment_item'; + + /** + * Constructor. + * + * @param int|object|array $item ID to load from the DB, or WC_Order_Item object. + */ + public function __construct( $item = 0 ) { + parent::__construct( $item ); + + if ( $item instanceof ShipmentItem ) { + $this->set_id( $item->get_id() ); + } elseif ( is_numeric( $item ) && $item > 0 ) { + $this->set_id( $item ); + } else { + $this->set_object_read( true ); + } + + $this->data_store = WC_Data_Store::load( 'shipment-item' ); + + // If we have an ID, load the user from the DB. + if ( $this->get_id() ) { + try { + $this->data_store->read( $this ); + } catch ( Exception $e ) { + $this->set_id( 0 ); + $this->set_object_read( true ); + } + } else { + $this->set_object_read( true ); + } + } + + /** + * Merge changes with data and clear. + * Overrides WC_Data::apply_changes. + * array_replace_recursive does not work well for order items because it merges taxes instead + * of replacing them. + * + * @since 3.2.0 + */ + public function apply_changes() { + if ( function_exists( 'array_replace' ) ) { + $this->data = array_replace( $this->data, $this->changes ); // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctions.array_replaceFound + } else { // PHP 5.2 compatibility. + foreach ( $this->changes as $key => $change ) { + $this->data[ $key ] = $change; + } + } + $this->changes = array(); + } + + /* + |-------------------------------------------------------------------------- + | Getters + |-------------------------------------------------------------------------- + */ + + public function get_type() { + return 'simple'; + } + + /** + * Get order ID this meta belongs to. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return int + */ + public function get_shipment_id( $context = 'view' ) { + return $this->get_prop( 'shipment_id', $context ); + } + + /** + * Get order ID this meta belongs to. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return int + */ + public function get_order_item_id( $context = 'view' ) { + return $this->get_prop( 'order_item_id', $context ); + } + + /** + * Get order ID this meta belongs to. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return int + */ + public function get_product_id( $context = 'view' ) { + return $this->get_prop( 'product_id', $context ); + } + + /** + * Get item parent id. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return int + */ + public function get_parent_id( $context = 'view' ) { + return $this->get_prop( 'parent_id', $context ); + } + + /** + * Get order ID this meta belongs to. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return int + */ + public function get_total( $context = 'view' ) { + return $this->get_prop( 'total', $context ); + } + + /** + * Get order ID this meta belongs to. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return int + */ + public function get_subtotal( $context = 'view' ) { + $subtotal = $this->get_prop( 'subtotal', $context ); + + if ( 'view' === $context && empty( $subtotal ) ) { + $subtotal = $this->get_total(); + } + + return $subtotal; + } + + /** + * Get quantity. + * + * @return int + */ + public function get_sku( $context = 'view' ) { + return $this->get_prop( 'sku', $context ); + } + + /** + * Get quantity. + * + * @return int + */ + public function get_quantity( $context = 'view' ) { + return $this->get_prop( 'quantity', $context ); + } + + /** + * Get weight. + * + * @return string + */ + public function get_weight( $context = 'view' ) { + return $this->get_prop( 'weight', $context ); + } + + /** + * Get width. + * + * @return string + */ + public function get_width( $context = 'view' ) { + return $this->get_prop( 'width', $context ); + } + + /** + * Get length. + * + * @return string + */ + public function get_length( $context = 'view' ) { + return $this->get_prop( 'length', $context ); + } + + /** + * Get height. + * + * @return string + */ + public function get_height( $context = 'view' ) { + return $this->get_prop( 'height', $context ); + } + + public function get_name( $context = 'view' ) { + $name = $this->get_prop( 'name', $context ); + + if ( 'view' === $context && empty( $name ) && ( $item = $this->get_order_item() ) ) { + $name = $item->get_name(); + } + + return $name; + } + + public function get_hs_code( $context = 'view' ) { + $legacy = $this->get_meta( '_dhl_hs_code', $context ); + $prop = $this->get_prop( 'hs_code', $context ); + + if ( '' === $prop && ! empty( $legacy ) ) { + $prop = $legacy; + } + + return $prop; + } + + public function get_manufacture_country( $context = 'view' ) { + $legacy = $this->get_meta( '_dhl_manufacture_country', $context ); + $prop = $this->get_prop( 'manufacture_country', $context ); + + if ( '' === $prop && ! empty( $legacy ) ) { + $prop = $legacy; + } + + return $prop; + } + + /** + * Get attributes. + * + * @return string[] + */ + public function get_attributes( $context = 'view' ) { + return $this->get_prop( 'attributes', $context ); + } + + public function has_attributes() { + $attributes = $this->get_attributes(); + + return ! empty( $attributes ); + } + + /** + * Get parent order object. + * + * @return SimpleShipment|ReturnShipment|Shipment + */ + public function get_shipment() { + if ( is_null( $this->shipment ) && 0 < $this->get_shipment_id() ) { + $this->shipment = wc_gzd_get_shipment( $this->get_shipment_id() ); + } + + $shipment = ( $this->shipment ) ? $this->shipment : false; + + return $shipment; + } + + /** + * Sets the linked shipment instance. + * + * @param Shipment $shipment + */ + public function set_shipment( &$shipment ) { + $this->shipment = $shipment; + } + + /** + * Syncs an item with either it's parent item or the corresponding order item. + * + * @param array $args + */ + public function sync( $args = array() ) { + $item = false; + + if ( $shipment = $this->get_shipment() ) { + if ( 'return' === $shipment->get_type() ) { + if ( $shipment = $this->get_shipment() ) { + if ( $order_shipment = $shipment->get_order_shipment() ) { + $item = $order_shipment->get_simple_shipment_item( $this->get_order_item_id() ); + } + } + } else { + $item = $this->get_order_item(); + } + } + + if ( is_a( $item, '\Vendidero\Germanized\Shipments\ShipmentItem' ) ) { + + $default_data = $item->get_data(); + + unset( $default_data['id'] ); + unset( $default_data['shipment_id'] ); + + $default_data['parent_id'] = $item->get_id(); + $args = wp_parse_args( $args, $default_data ); + + } elseif ( is_a( $item, 'WC_Order_Item' ) ) { + + if ( is_callable( array( $item, 'get_variation_id' ) ) && is_callable( array( $item, 'get_product_id' ) ) ) { + $this->set_product_id( $item->get_variation_id() ? $item->get_variation_id() : $item->get_product_id() ); + } elseif ( is_callable( array( $item, 'get_product_id' ) ) ) { + $this->set_product_id( $item->get_product_id() ); + } + + $args = wp_parse_args( + $args, + array( + 'quantity' => 1, + ) + ); + + $product = $this->get_product(); + $s_product = wc_gzd_shipments_get_product( $product ); + + /** + * Calculate the order item total per unit to make sure it is independent from + * shipment item quantity. + */ + $tax_total = is_callable( array( $item, 'get_total_tax' ) ) ? ( (float) $item->get_total_tax() / $item->get_quantity() ) * $args['quantity'] : 0; + $total = is_callable( array( $item, 'get_total' ) ) ? ( (float) $item->get_total() / $item->get_quantity() ) * $args['quantity'] : 0; + $subtotal = is_callable( array( $item, 'get_subtotal' ) ) ? (float) $item->get_subtotal() / $item->get_quantity() * $args['quantity'] : 0; + $tax_subtotal = is_callable( array( $item, 'get_subtotal_tax' ) ) ? (float) $item->get_subtotal_tax() / $item->get_quantity() * $args['quantity'] : 0; + $meta = $item->get_formatted_meta_data( apply_filters( "{$this->get_hook_prefix()}hide_meta_prefix", '_', $this ), apply_filters( "{$this->get_hook_prefix()}include_all_meta", false, $this ) ); + $attributes = array(); + + foreach ( $meta as $meta_id => $entry ) { + $attributes[] = array( + 'key' => $entry->key, + 'value' => str_replace( array( '

', '

' ), '', $entry->display_value ), + 'label' => $entry->display_key, + 'order_item_meta_id' => $meta_id, + ); + } + + $args = wp_parse_args( + $args, + array( + 'order_item_id' => $item->get_id(), + 'quantity' => 1, + 'name' => $item->get_name(), + 'sku' => $product ? $product->get_sku() : '', + 'total' => $total + $tax_total, + 'subtotal' => $subtotal + $tax_subtotal, + 'weight' => $product ? wc_get_weight( $product->get_weight(), $shipment->get_weight_unit() ) : '', + 'length' => $product ? wc_get_dimension( $product->get_length(), $shipment->get_dimension_unit() ) : '', + 'width' => $product ? wc_get_dimension( $product->get_width(), $shipment->get_dimension_unit() ) : '', + 'height' => $product ? wc_get_dimension( $product->get_height(), $shipment->get_dimension_unit() ) : '', + 'hs_code' => $s_product ? $s_product->get_hs_code() : '', + 'manufacture_country' => $s_product ? $s_product->get_manufacture_country() : '', + 'attributes' => $attributes, + ) + ); + } + + $this->set_props( $args ); + + /** + * Action that fires after a shipment item has been synced. Syncing is used to + * keep the shipment item in sync with the corresponding order item or parent shipment item. + * + * @param WC_Order_Item|ShipmentItem $item The order item object or parent shipment item. + * @param array $args Array containing props in key => value pairs which have been updated. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_shipment_item_synced', $this, $item, $args ); + } + + public function get_order_item() { + if ( is_null( $this->order_item ) && 0 < $this->get_order_item_id() ) { + if ( $shipment = $this->get_shipment() ) { + + if ( $order = $shipment->get_order() ) { + $this->order_item = $order->get_item( $this->get_order_item_id() ); + } + } + } + + $item = ( $this->order_item ) ? $this->order_item : false; + + return $item; + } + + public function get_product() { + if ( is_null( $this->product ) && 0 < $this->get_product_id() ) { + $this->product = wc_get_product( $this->get_product_id() ); + } + + $product = ( $this->product ) ? $this->product : false; + + return $product; + } + + /* + |-------------------------------------------------------------------------- + | Setters + |-------------------------------------------------------------------------- + */ + + /** + * Set order ID. + * + * @param int $value Order ID. + */ + public function set_shipment_id( $value ) { + $this->order_item = null; + $this->shipment = null; + + $this->set_prop( 'shipment_id', absint( $value ) ); + } + + /** + * Set order ID. + * + * @param int $value Order ID. + */ + public function set_order_item_id( $value ) { + $this->set_prop( 'order_item_id', absint( $value ) ); + } + + /** + * Set order ID. + * + * @param int $value Order ID. + */ + public function set_total( $value ) { + $value = wc_format_decimal( $value ); + + if ( ! is_numeric( $value ) ) { + $value = 0; + } + + $this->set_prop( 'total', $value ); + } + + /** + * Set order ID. + * + * @param int $value Order ID. + */ + public function set_subtotal( $value ) { + $value = wc_format_decimal( $value ); + + if ( ! is_numeric( $value ) ) { + $value = 0; + } + + $this->set_prop( 'subtotal', $value ); + } + + /** + * Set order ID. + * + * @param int $value Order ID. + */ + public function set_product_id( $value ) { + $this->product = null; + $this->set_prop( 'product_id', absint( $value ) ); + } + + /** + * Set parent id. + * + * @param int $value parent id. + */ + public function set_parent_id( $value ) { + $this->set_prop( 'parent_id', absint( $value ) ); + } + + public function set_sku( $sku ) { + $this->set_prop( 'sku', $sku ); + } + + /** + * Set weight in kg + * + * @param $weight + */ + public function set_weight( $weight ) { + $this->set_prop( 'weight', '' === $weight ? '' : wc_format_decimal( $weight ) ); + } + + /** + * Set width in cm + * + * @param $weight + */ + public function set_width( $width ) { + $this->set_prop( 'width', '' === $width ? '' : wc_format_decimal( $width ) ); + } + + /** + * Set length in cm + * + * @param $weight + */ + public function set_length( $length ) { + $this->set_prop( 'length', '' === $length ? '' : wc_format_decimal( $length ) ); + } + + /** + * Set height in cm + * + * @param $weight + */ + public function set_height( $height ) { + $this->set_prop( 'height', '' === $height ? '' : wc_format_decimal( $height ) ); + } + + public function get_dimensions( $context = 'view' ) { + return array( + 'length' => $this->get_length( $context ), + 'width' => $this->get_width( $context ), + 'height' => $this->get_height( $context ), + ); + } + + public function set_quantity( $quantity ) { + $this->set_prop( 'quantity', absint( $quantity ) ); + } + + public function set_name( $name ) { + $this->set_prop( 'name', $name ); + } + + public function set_hs_code( $code ) { + $this->set_prop( 'hs_code', $code ); + } + + public function set_manufacture_country( $country ) { + $this->set_prop( 'manufacture_country', wc_strtoupper( $country ) ); + } + + /** + * Set attributes + * + * @param $attributes + */ + public function set_attributes( $attributes ) { + $this->set_prop( 'attributes', (array) $attributes ); + } + + /* + |-------------------------------------------------------------------------- + | Other Methods + |-------------------------------------------------------------------------- + */ +} diff --git a/packages/woocommerce-germanized-shipments/src/ShipmentQuery.php b/packages/woocommerce-germanized-shipments/src/ShipmentQuery.php new file mode 100644 index 000000000..1d098969b --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/ShipmentQuery.php @@ -0,0 +1,540 @@ + array_keys( wc_gzd_get_shipment_statuses() ), + 'limit' => 10, + 'order_id' => '', + 'parent_id' => '', + 'type' => 'simple', + 'country' => '', + 'tracking_id' => '', + 'order' => 'DESC', + 'orderby' => 'date_created', + 'return' => 'objects', + 'page' => 1, + 'offset' => '', + 'paginate' => false, + 'search' => '', + 'search_columns' => array(), + ); + } + + /** + * Get shipments matching the current query vars. + * + * @return Shipment[] Array containing Shipments. + */ + public function get_shipments() { + /** + * Filter to adjust query arguments passed to a Shipment query. + * + * @param array $args The arguments passed. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + $args = apply_filters( 'woocommerce_gzd_shipment_query_args', $this->get_query_vars() ); + $args = WC_Data_Store::load( 'shipment' )->get_query_args( $args ); + + $this->query( $args ); + + /** + * Filter to adjust the Shipment query result. + * + * @param Shipment[] $results Shipment results. + * @param array $args The arguments passed. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipment_query', $this->results, $args ); + } + + public function get_total() { + return $this->total_shipments; + } + + public function get_max_num_pages() { + return $this->max_num_pages; + } + + /** + * Query shipments. + * + * @param array $query_args + */ + protected function query( $query_args ) { + global $wpdb; + + $this->args = $query_args; + $this->parse_query(); + $this->prepare_query(); + + $qv =& $this->args; + + $this->results = null; + + if ( null === $this->results ) { + $this->request = "SELECT $this->query_fields $this->query_from $this->query_where $this->query_orderby $this->query_limit"; + + if ( is_array( $qv['fields'] ) || 'objects' === $qv['fields'] ) { + $this->results = $wpdb->get_results( $this->request ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + } else { + $this->results = $wpdb->get_col( $this->request ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + } + + if ( isset( $qv['count_total'] ) && $qv['count_total'] ) { + $found_shipments_query = 'SELECT FOUND_ROWS()'; + $this->total_shipments = (int) $wpdb->get_var( $found_shipments_query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + $this->max_num_pages = ceil( $this->total_shipments / $qv['posts_per_page'] ); + } + } + + if ( ! $this->results ) { + return; + } + + if ( 'objects' === $qv['fields'] ) { + foreach ( $this->results as $key => $shipment ) { + $this->results[ $key ] = wc_gzd_get_shipment( $shipment ); + } + } + } + + /** + * Parse the query before preparing it. + */ + protected function parse_query() { + + if ( isset( $this->args['order_id'] ) ) { + $this->args['order_id'] = absint( $this->args['order_id'] ); + } + + if ( isset( $this->args['parent_id'] ) ) { + $this->args['parent_id'] = absint( $this->args['parent_id'] ); + } + + if ( isset( $this->args['tracking_id'] ) ) { + $this->args['tracking_id'] = sanitize_key( $this->args['tracking_id'] ); + } + + if ( isset( $this->args['status'] ) ) { + $this->args['status'] = (array) $this->args['status']; + $this->args['status'] = array_map( 'sanitize_key', $this->args['status'] ); + } + + if ( isset( $this->args['type'] ) ) { + $this->args['type'] = (array) $this->args['type']; + $this->args['type'] = array_map( 'wc_clean', $this->args['type'] ); + } + + if ( isset( $this->args['country'] ) ) { + $countries = isset( WC()->countries ) ? WC()->countries : false; + + if ( $countries && is_a( $countries, 'WC_Countries' ) ) { + + // Reverse search by country name + if ( $key = array_search( $this->args['country'], $countries->get_countries(), true ) ) { + $this->args['country'] = $key; + } + } + + // Country Code ISO + $this->args['country'] = strtoupper( substr( $this->args['country'], 0, 2 ) ); + } + + if ( isset( $this->args['search'] ) ) { + $this->args['search'] = wc_clean( $this->args['search'] ); + + if ( ! isset( $this->args['search_columns'] ) ) { + $this->args['search_columns'] = array(); + } + } + + if ( isset( $this->args['orderby'] ) ) { + if ( 'weight' === $this->args['orderby'] ) { + $this->args['meta_query'][] = array( + 'relation' => 'OR', + array( + 'key' => '_weight', + 'compare' => 'NOT EXISTS', + ), + array( + 'key' => '_weight', + 'compare' => '>=', + 'value' => 0, + ), + ); + + $this->args['orderby'] = 'meta_value_num'; + } + } + } + + /** + * Prepare the query for DB usage. + */ + protected function prepare_query() { + global $wpdb; + + if ( is_array( $this->args['fields'] ) ) { + $this->args['fields'] = array_unique( $this->args['fields'] ); + + $this->query_fields = array(); + + foreach ( $this->args['fields'] as $field ) { + $field = 'ID' === $field ? 'shipment_id' : sanitize_key( $field ); + $this->query_fields[] = "$wpdb->gzd_shipments.$field"; + } + + $this->query_fields = implode( ',', $this->query_fields ); + + } elseif ( 'objects' === $this->args['fields'] ) { + $this->query_fields = "$wpdb->gzd_shipments.*"; + } else { + $this->query_fields = "$wpdb->gzd_shipments.shipment_id"; + } + + if ( isset( $this->args['count_total'] ) && $this->args['count_total'] ) { + $this->query_fields = 'SQL_CALC_FOUND_ROWS ' . $this->query_fields; + } + + $this->query_from = "FROM $wpdb->gzd_shipments"; + $this->query_where = 'WHERE 1=1'; + + // order id + if ( isset( $this->args['order_id'] ) ) { + $this->query_where .= $wpdb->prepare( ' AND shipment_order_id = %d', $this->args['order_id'] ); + } + + // tracking id + if ( isset( $this->args['tracking_id'] ) ) { + $this->query_where .= $wpdb->prepare( " AND shipment_tracking_id IN ('%s')", $this->args['tracking_id'] ); // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.QuotedSimplePlaceholder + } + + // parent id + if ( isset( $this->args['parent_id'] ) ) { + $this->query_where .= $wpdb->prepare( ' AND shipment_parent_id = %d', $this->args['parent_id'] ); + } + + // country + if ( isset( $this->args['country'] ) ) { + $this->query_where .= $wpdb->prepare( " AND shipment_country IN ('%s')", $this->args['country'] ); // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.QuotedSimplePlaceholder + } + + // type + if ( isset( $this->args['type'] ) ) { + $types = $this->args['type']; + $p_types = array(); + + foreach ( $types as $type ) { + $p_types[] = $wpdb->prepare( 'shipment_type = %s', $type ); + } + + $where_type = implode( ' OR ', $p_types ); + + if ( ! empty( $where_type ) ) { + $this->query_where .= " AND ($where_type)"; + } + } + + // status + if ( isset( $this->args['status'] ) ) { + $stati = $this->args['status']; + $p_status = array(); + + foreach ( $stati as $status ) { + $p_status[] = $wpdb->prepare( 'shipment_status = %s', $status ); + } + + $where_status = implode( ' OR ', $p_status ); + + if ( ! empty( $where_status ) ) { + $this->query_where .= " AND ($where_status)"; + } + } + + // Search + $search = ''; + + if ( isset( $this->args['search'] ) ) { + $search = trim( $this->args['search'] ); + } + + if ( $search ) { + + $leading_wild = ( ltrim( $search, '*' ) !== $search ); + $trailing_wild = ( rtrim( $search, '*' ) !== $search ); + + if ( $leading_wild && $trailing_wild ) { + $wild = 'both'; + } elseif ( $leading_wild ) { + $wild = 'leading'; + } elseif ( $trailing_wild ) { + $wild = 'trailing'; + } else { + $wild = false; + } + if ( $wild ) { + $search = trim( $search, '*' ); + } + + $search_columns = array(); + + if ( $this->args['search_columns'] ) { + $search_columns = array_intersect( $this->args['search_columns'], array( 'shipment_id', 'shipment_country', 'shipment_tracking_id', 'shipment_order_id', 'shipment_shipping_provider', 'shipment_shipping_method', 'shipment_search_index' ) ); + } + + if ( ! $search_columns ) { + if ( is_numeric( $search ) ) { + $search_columns = array( 'shipment_id', 'shipment_order_id', 'shipment_tracking_id' ); + } elseif ( strlen( $search ) === 2 ) { + $search_columns = array( 'shipment_country' ); + } else { + $search_columns = array( 'shipment_id', 'shipment_country', 'shipment_tracking_id', 'shipment_order_id', 'shipment_search_index' ); + } + } + + /** + * Filters the columns to search in a ShipmentQuery search. + * + * The default columns depend on the search term, and include 'shipment_id', 'shipment_country', + * 'shipment_tracking_id', 'shipment_order_id', 'shipment_shipping_provider' and 'shipment_shipping_method'. + * + * @since 3.0.0 + * + * @param string[] $search_columns Array of column names to be searched. + * @param string $search Text being searched. + * @param ShipmentQuery $this The current ShipmentQuery instance. + * + * @package Vendidero/Germanized/Shipments + */ + $search_columns = apply_filters( 'woocommerce_gzd_shipment_search_columns', $search_columns, $search, $this ); + + $this->query_where .= $this->get_search_sql( $search, $search_columns, $wild ); + } + + // Parse and sanitize 'include', for use by 'orderby' as well as 'include' below. + if ( ! empty( $this->args['include'] ) ) { + $include = wp_parse_id_list( $this->args['include'] ); + } else { + $include = false; + } + + // Meta query. + $this->meta_query = new WP_Meta_Query(); + $this->meta_query->parse_query_vars( $this->args ); + + if ( ! empty( $this->meta_query->queries ) ) { + $clauses = $this->meta_query->get_sql( 'gzd_shipment', $wpdb->gzd_shipments, 'shipment_id', $this ); + $this->query_from .= $clauses['join']; + $this->query_where .= $clauses['where']; + + if ( $this->meta_query->has_or_relation() ) { + $this->query_fields = 'DISTINCT ' . $this->query_fields; + } + } + + // sorting + $this->args['order'] = isset( $this->args['order'] ) ? strtoupper( $this->args['order'] ) : ''; + $order = $this->parse_order( $this->args['order'] ); + + if ( empty( $this->args['orderby'] ) ) { + // Default order is by 'user_login'. + $ordersby = array( 'date_created' => $order ); + } elseif ( is_array( $this->args['orderby'] ) ) { + $ordersby = $this->args['orderby']; + } else { + // 'orderby' values may be a comma- or space-separated list. + $ordersby = preg_split( '/[,\s]+/', $this->args['orderby'] ); + } + + $orderby_array = array(); + + foreach ( $ordersby as $_key => $_value ) { + if ( ! $_value ) { + continue; + } + + if ( is_int( $_key ) ) { + // Integer key means this is a flat array of 'orderby' fields. + $_orderby = $_value; + $_order = $order; + } else { + // Non-integer key means this the key is the field and the value is ASC/DESC. + $_orderby = $_key; + $_order = $_value; + } + + $parsed = $this->parse_orderby( $_orderby ); + + if ( ! $parsed ) { + continue; + } + + $orderby_array[] = $parsed . ' ' . $this->parse_order( $_order ); + } + + // If no valid clauses were found, order by user_login. + if ( empty( $orderby_array ) ) { + $orderby_array[] = "shipment_id $order"; + } + + $this->query_orderby = 'ORDER BY ' . implode( ', ', $orderby_array ); + + // limit + if ( isset( $this->args['posts_per_page'] ) && $this->args['posts_per_page'] > 0 ) { + if ( isset( $this->args['offset'] ) ) { + $this->query_limit = $wpdb->prepare( 'LIMIT %d, %d', $this->args['offset'], $this->args['posts_per_page'] ); + } else { + $this->query_limit = $wpdb->prepare( 'LIMIT %d, %d', $this->args['posts_per_page'] * ( $this->args['page'] - 1 ), $this->args['posts_per_page'] ); + } + } + + if ( ! empty( $include ) ) { + // Sanitized earlier. + $ids = implode( ',', $include ); + $this->query_where .= " AND $wpdb->gzd_shipments.shipment_id IN ($ids)"; + } elseif ( ! empty( $this->args['exclude'] ) ) { + $ids = implode( ',', wp_parse_id_list( $this->args['exclude'] ) ); + $this->query_where .= " AND $wpdb->gzd_shipments.shipment_id NOT IN ($ids)"; + } + + // Date queries are allowed for the user_registered field. + if ( ! empty( $this->args['date_query'] ) && is_array( $this->args['date_query'] ) ) { + $date_query = new WP_Date_Query( $this->args['date_query'], 'shipment_date_created' ); + $this->query_where .= $date_query->get_sql(); + } + } + + /** + * Used internally to generate an SQL string for searching across multiple columns + * + * @since 3.0.6 + * + * @global wpdb $wpdb WordPress database abstraction object. + * + * @param string $string + * @param array $cols + * @param bool $wild Whether to allow wildcard searches. Default is false for Network Admin, true for single site. + * Single site allows leading and trailing wildcards, Network Admin only trailing. + * @return string + */ + protected function get_search_sql( $string, $cols, $wild = false ) { + global $wpdb; + + $searches = array(); + $leading_wild = ( 'leading' === $wild || 'both' === $wild ) ? '%' : ''; + $trailing_wild = ( 'trailing' === $wild || 'both' === $wild ) ? '%' : ''; + $like = $leading_wild . $wpdb->esc_like( $string ) . $trailing_wild; + + foreach ( $cols as $col ) { + if ( 'ID' === $col ) { + $searches[] = $wpdb->prepare( "$col = %s", $string ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared + } else { + $searches[] = $wpdb->prepare( "$col LIKE %s", $like ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared + } + } + + return ' AND (' . implode( ' OR ', $searches ) . ')'; + } + + /** + * Parse orderby statement. + * + * @param string $orderby + * @return string + */ + protected function parse_orderby( $orderby ) { + global $wpdb; + + $meta_query_clauses = $this->meta_query->get_clauses(); + $_orderby = ''; + + if ( in_array( $orderby, array( 'country', 'status', 'tracking_id', 'date_created', 'order_id' ), true ) ) { + $_orderby = 'shipment_' . $orderby; + } elseif ( 'date' === $orderby ) { + $_orderby = 'shipment_date_created'; + } elseif ( 'ID' === $orderby || 'id' === $orderby ) { + $_orderby = 'shipment_id'; + } elseif ( 'meta_value' === $orderby || $this->get( 'meta_key' ) === $orderby ) { + $_orderby = "$wpdb->gzd_shipmentmeta.meta_value"; + } elseif ( 'meta_value_num' === $orderby ) { + $_orderby = "$wpdb->gzd_shipmentmeta.meta_value+0"; + } elseif ( 'include' === $orderby && ! empty( $this->args['include'] ) ) { + $include = wp_parse_id_list( $this->args['include'] ); + $include_sql = implode( ',', $include ); + $_orderby = "FIELD( $wpdb->gzd_shipments.shipment_id, $include_sql )"; + } elseif ( isset( $meta_query_clauses[ $orderby ] ) ) { + $meta_clause = $meta_query_clauses[ $orderby ]; + $_orderby = sprintf( 'CAST(%s.meta_value AS %s)', esc_sql( $meta_clause['alias'] ), esc_sql( $meta_clause['cast'] ) ); + } + + return $_orderby; + } + + /** + * Parse order statement. + * + * @param string $order + * @return string + */ + protected function parse_order( $order ) { + if ( ! is_string( $order ) || empty( $order ) ) { + return 'DESC'; + } + + if ( 'ASC' === strtoupper( $order ) ) { + return 'ASC'; + } else { + return 'DESC'; + } + } +} diff --git a/packages/woocommerce-germanized-shipments/src/ShipmentReturnItem.php b/packages/woocommerce-germanized-shipments/src/ShipmentReturnItem.php new file mode 100644 index 000000000..14bba66d1 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/ShipmentReturnItem.php @@ -0,0 +1,32 @@ + '', + ); + + public function get_type() { + return 'return'; + } + + public function get_return_reason_code( $context = 'view' ) { + return $this->get_prop( 'return_reason_code', $context ); + } + + public function set_return_reason_code( $code ) { + $this->set_prop( 'return_reason_code', $code ); + } +} diff --git a/packages/woocommerce-germanized-shipments/src/ShippingProvider/Auto.php b/packages/woocommerce-germanized-shipments/src/ShippingProvider/Auto.php new file mode 100644 index 000000000..f4e4a75c2 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/ShippingProvider/Auto.php @@ -0,0 +1,562 @@ + '', + 'label_minimum_shipment_weight' => '', + 'label_auto_enable' => false, + 'label_auto_shipment_status' => 'gzd-processing', + 'label_return_auto_enable' => false, + 'label_return_auto_shipment_status' => 'gzd-processing', + 'label_auto_shipment_status_shipped' => false, + ); + + public function get_label_default_shipment_weight( $context = 'view' ) { + $weight = $this->get_prop( 'label_default_shipment_weight', $context ); + + if ( 'view' === $context && '' === $weight ) { + $weight = $this->get_default_label_default_shipment_weight(); + } + + return $weight; + } + + protected function get_default_label_default_shipment_weight() { + return 0; + } + + public function get_label_minimum_shipment_weight( $context = 'view' ) { + $weight = $this->get_prop( 'label_minimum_shipment_weight', $context ); + + if ( 'view' === $context && '' === $weight ) { + $weight = $this->get_default_label_minimum_shipment_weight(); + } + + return $weight; + } + + protected function get_default_label_minimum_shipment_weight() { + return 0.5; + } + + /** + * @param false|Shipment $shipment + * + * @return boolean + */ + public function automatically_generate_label( $shipment = false ) { + $setting_key = 'label_auto_enable'; + + if ( $shipment ) { + if ( 'return' === $shipment->get_type() ) { + $setting_key = 'label_return_auto_enable'; + } + + return wc_string_to_bool( $this->get_shipment_setting( $shipment, $setting_key, false ) ); + } else { + return wc_string_to_bool( $this->get_setting( $setting_key, false ) ); + } + } + + /** + * @param false|Shipment $shipment + * + * @return string + */ + public function get_label_automation_shipment_status( $shipment = false ) { + $setting_key = 'label_auto_shipment_status'; + + if ( $shipment ) { + if ( 'return' === $shipment->get_type() ) { + $setting_key = 'label_return_auto_shipment_status'; + } + + return $this->get_shipment_setting( $shipment, $setting_key, 'gzd-processing' ); + } else { + return $this->get_setting( $setting_key, 'gzd-processing' ); + } + } + + public function automatically_set_shipment_status_shipped( $shipment = false ) { + $setting_key = 'label_auto_shipment_status_shipped'; + + if ( $shipment ) { + return wc_string_to_bool( $this->get_shipment_setting( $shipment, $setting_key, false ) ); + } else { + return wc_string_to_bool( $this->get_setting( $setting_key, false ) ); + } + } + + public function get_label_auto_enable( $context = 'view' ) { + return $this->get_prop( 'label_auto_enable', $context ); + } + + public function get_label_auto_shipment_status_shipped( $context = 'view' ) { + return $this->get_prop( 'label_auto_shipment_status_shipped', $context ); + } + + public function get_label_auto_shipment_status( $context = 'view' ) { + return $this->get_prop( 'label_auto_shipment_status', $context ); + } + + public function automatically_generate_return_label() { + return $this->get_label_return_auto_enable(); + } + + public function get_label_return_auto_enable( $context = 'view' ) { + return $this->get_prop( 'label_return_auto_enable', $context ); + } + + public function get_label_return_auto_shipment_status( $context = 'view' ) { + return $this->get_prop( 'label_return_auto_shipment_status', $context ); + } + + public function is_sandbox() { + return false; + } + + public function set_label_default_shipment_weight( $weight ) { + $this->set_prop( 'label_default_shipment_weight', ( '' === $weight ? '' : wc_format_decimal( $weight ) ) ); + } + + public function set_label_minimum_shipment_weight( $weight ) { + $this->set_prop( 'label_minimum_shipment_weight', ( '' === $weight ? '' : wc_format_decimal( $weight ) ) ); + } + + public function set_label_auto_enable( $enable ) { + $this->set_prop( 'label_auto_enable', wc_string_to_bool( $enable ) ); + } + + public function set_label_auto_shipment_status_shipped( $enable ) { + $this->set_prop( 'label_auto_shipment_status_shipped', wc_string_to_bool( $enable ) ); + } + + public function set_label_auto_shipment_status( $status ) { + $this->set_prop( 'label_auto_shipment_status', $status ); + } + + public function set_label_return_auto_enable( $enable ) { + $this->set_prop( 'label_return_auto_enable', wc_string_to_bool( $enable ) ); + } + + public function set_label_return_auto_shipment_status( $status ) { + $this->set_prop( 'label_return_auto_shipment_status', $status ); + } + + public function get_label_classname( $type ) { + return '\Vendidero\Germanized\Shipments\Labels\Simple'; + } + + /** + * Whether or not this instance is a manual integration. + * Manual integrations are constructed dynamically from DB and do not support + * automatic shipment handling, e.g. label creation. + * + * @return bool + */ + public function is_manual_integration() { + return false; + } + + /** + * Whether or not this instance supports a certain label type. + * + * @param string $label_type The label type e.g. simple or return. + * + * @return bool + */ + public function supports_labels( $label_type, $shipment = false ) { + return true; + } + + /** + * @param \Vendidero\Germanized\Shipments\Shipment $shipment + * + * @return mixed|void + */ + public function get_label( $shipment ) { + $type = wc_gzd_get_label_type_by_shipment( $shipment ); + $label = wc_gzd_get_label_by_shipment( $shipment, $type ); + + return apply_filters( "{$this->get_hook_prefix()}label", $label, $shipment, $this ); + } + + /** + * @param \Vendidero\Germanized\Shipments\Shipment $shipment + */ + public function get_label_fields_html( $shipment ) { + /** + * Setup local variables + */ + $settings = $this->get_label_fields( $shipment ); + $provider = $this; + + if ( is_wp_error( $settings ) ) { + $error = $settings; + + ob_start(); + include Package::get_path() . '/includes/admin/views/label/html-shipment-label-backbone-error.php'; + $html = ob_get_clean(); + } else { + ob_start(); + include Package::get_path() . '/includes/admin/views/label/html-shipment-label-backbone-form.php'; + $html = ob_get_clean(); + } + + return apply_filters( "{$this->get_hook_prefix()}label_fields_html", $html, $shipment, $this ); + } + + protected function get_automation_settings( $for_shipping_method = false ) { + $settings = array( + array( + 'title' => _x( 'Automation', 'shipments', 'woocommerce-germanized' ), + 'allow_override' => true, + 'type' => 'title', + 'id' => 'shipping_provider_label_auto_options', + ), + ); + + $shipment_statuses = array_diff_key( wc_gzd_get_shipment_statuses(), array_fill_keys( array( 'gzd-draft', 'gzd-delivered', 'gzd-returned', 'gzd-requested' ), '' ) ); + + $settings = array_merge( + $settings, + array( + array( + 'title' => _x( 'Labels', 'shipments', 'woocommerce-germanized' ), + 'desc' => _x( 'Automatically create labels for shipments.', 'shipments', 'woocommerce-germanized' ), + 'id' => 'label_auto_enable', + 'type' => 'gzd_toggle', + 'value' => wc_bool_to_string( $this->get_setting( 'label_auto_enable' ) ), + ), + + array( + 'title' => _x( 'Status', 'shipments', 'woocommerce-germanized' ), + 'type' => 'select', + 'id' => 'label_auto_shipment_status', + 'desc' => '
' . _x( 'Choose a shipment status which should trigger generation of a label.', 'shipments', 'woocommerce-germanized' ) . ' ' . ( 'yes' === Package::get_setting( 'auto_enable' ) ? sprintf( _x( 'Your current default shipment status is: %s.', 'shipments', 'woocommerce-germanized' ), wc_gzd_get_shipment_status_name( Package::get_setting( 'auto_default_status' ) ) ) : '' ) . '
', + 'options' => $shipment_statuses, + 'class' => 'wc-enhanced-select', + 'custom_attributes' => array( 'data-show_if_label_auto_enable' => '' ), + 'value' => $this->get_setting( 'label_auto_shipment_status' ), + ), + + array( + 'title' => _x( 'Shipment Status', 'shipments', 'woocommerce-germanized' ), + 'desc' => _x( 'Mark shipment as shipped after label has been created successfully.', 'shipments', 'woocommerce-germanized' ), + 'id' => 'label_auto_shipment_status_shipped', + 'type' => 'gzd_toggle', + 'value' => wc_bool_to_string( $this->get_setting( 'label_auto_shipment_status_shipped' ) ), + ), + ) + ); + + if ( $this->supports_labels( 'return' ) ) { + $settings = array_merge( + $settings, + array( + array( + 'title' => _x( 'Returns', 'shipments', 'woocommerce-germanized' ), + 'desc' => _x( 'Automatically create labels for returns.', 'shipments', 'woocommerce-germanized' ), + 'id' => 'label_return_auto_enable', + 'type' => 'gzd_toggle', + 'value' => wc_bool_to_string( $this->get_setting( 'label_return_auto_enable' ) ), + ), + + array( + 'title' => _x( 'Status', 'shipments', 'woocommerce-germanized' ), + 'type' => 'select', + 'id' => 'label_return_auto_shipment_status', + 'desc' => '
' . _x( 'Choose a shipment status which should trigger generation of a return label.', 'shipments', 'woocommerce-germanized' ) . '
', + 'options' => $shipment_statuses, + 'class' => 'wc-enhanced-select', + 'custom_attributes' => array( 'data-show_if_label_return_auto_enable' => '' ), + 'value' => $this->get_setting( 'label_return_auto_shipment_status' ), + ), + ) + ); + } + + $settings = array_merge( + $settings, + array( + array( + 'type' => 'sectionend', + 'id' => 'shipping_provider_label_auto_options', + ), + ) + ); + + return $settings; + } + + public function get_settings_help_pointers( $section = '' ) { + return array(); + } + + protected function get_label_settings( $for_shipping_method = false ) { + $settings = array( + array( + 'title' => '', + 'type' => 'title', + 'id' => 'shipping_provider_label_options', + ), + + array( + 'title' => _x( 'Default content weight (kg)', 'shipments', 'woocommerce-germanized' ), + 'type' => 'text', + 'desc' => _x( 'Choose a default shipment content weight to be used for labels if no weight has been applied to the shipment.', 'shipments', 'woocommerce-germanized' ), + 'desc_tip' => true, + 'id' => 'label_default_shipment_weight', + 'css' => 'max-width: 60px;', + 'class' => 'wc_input_decimal', + 'default' => $this->get_default_label_default_shipment_weight(), + 'value' => $this->get_setting( 'label_default_shipment_weight' ), + ), + + array( + 'title' => _x( 'Minimum weight (kg)', 'shipments', 'woocommerce-germanized' ), + 'type' => 'text', + 'desc' => _x( 'Choose a minimum weight to be used for labels e.g. to prevent low shipment weight errors.', 'shipments', 'woocommerce-germanized' ), + 'desc_tip' => true, + 'id' => 'label_minimum_shipment_weight', + 'css' => 'max-width: 60px;', + 'class' => 'wc_input_decimal', + 'default' => $this->get_default_label_minimum_shipment_weight(), + 'value' => $this->get_setting( 'label_minimum_shipment_weight' ), + ), + + array( + 'type' => 'sectionend', + 'id' => 'shipping_provider_label_options', + ), + ); + + return $settings; + } + + protected function get_available_base_countries() { + $countries = array(); + + if ( function_exists( 'WC' ) && WC()->countries ) { + $countries = WC()->countries->get_countries(); + } + + return $countries; + } + + public function get_setting_sections() { + $sections = array( + '' => _x( 'General', 'shipments', 'woocommerce-germanized' ), + 'label' => _x( 'Labels', 'shipments', 'woocommerce-germanized' ), + 'automation' => _x( 'Automation', 'shipments', 'woocommerce-germanized' ), + ); + + $sections = array_replace_recursive( $sections, parent::get_setting_sections() ); + + return $sections; + } + + /** + * @param \Vendidero\Germanized\Shipments\Shipment $shipment + */ + public function get_label_fields( $shipment ) { + if ( 'return' === $shipment->get_type() ) { + return $this->get_return_label_fields( $shipment ); + } else { + return $this->get_simple_label_fields( $shipment ); + } + } + + /** + * @param \Vendidero\Germanized\Shipments\Shipment $shipment + */ + protected function get_simple_label_fields( $shipment ) { + $default = $this->get_default_label_product( $shipment ); + $available = $this->get_available_label_products( $shipment ); + + $settings = array( + array( + 'id' => 'product_id', + 'label' => sprintf( _x( '%s Product', 'shipments', 'woocommerce-germanized' ), $this->get_title() ), + 'description' => '', + 'options' => $this->get_available_label_products( $shipment ), + 'value' => $default && array_key_exists( $default, $available ) ? $default : '', + 'type' => 'select', + ), + ); + + return $settings; + } + + /** + * @param \Vendidero\Germanized\Shipments\Shipment $shipment + */ + protected function get_return_label_fields( $shipment ) { + return $this->get_simple_label_fields( $shipment ); + } + + /** + * @param Shipment $shipment + * @param $props + * + * @return \WP_Error|mixed + */ + protected function validate_label_request( $shipment, $props ) { + return $props; + } + + /** + * @param Shipment $shipment + * + * @return array + */ + protected function get_default_label_props( $shipment ) { + $default = array( + 'shipping_provider' => $this->get_name(), + 'weight' => wc_gzd_get_shipment_label_weight( $shipment ), + 'net_weight' => wc_gzd_get_shipment_label_weight( $shipment, true ), + 'shipment_id' => $shipment->get_id(), + 'services' => array(), + 'product_id' => $this->get_default_label_product( $shipment ), + ); + + $dimensions = wc_gzd_get_shipment_label_dimensions( $shipment ); + $default = array_merge( $default, $dimensions ); + + return $default; + } + + /** + * @param \Vendidero\Germanized\Shipments\Shipment $shipment + * @param mixed $props + */ + public function create_label( $shipment, $props = false ) { + /** + * In case props is false this indicates an automatic (non-manual) request. + */ + if ( false === $props ) { + $props = $this->get_default_label_props( $shipment ); + } elseif ( is_array( $props ) ) { + $fields = $this->get_label_fields( $shipment ); + + /** + * By default checkbox fields won't be transmitted via POST data. + * In case the values does not exist within props, assume not checked. + */ + foreach ( $fields as $field ) { + if ( ! isset( $field['value'] ) ) { + continue; + } + + if ( 'checkbox' === $field['type'] && ! isset( $props[ $field['id'] ] ) ) { + // Exclude array fields from default checkbox handling + if ( isset( $field['name'] ) && strstr( $field['name'], '[]' ) ) { + continue; + } + + $props[ $field['id'] ] = 'no'; + } elseif ( 'multiselect' === $field['type'] ) { + if ( isset( $props[ $field['id'] ] ) ) { + $props[ $field['id'] ] = (array) $props[ $field['id'] ]; + } + } + } + + /** + * Merge with default data. That needs to be done after manually + * parsing checkboxes as missing data would be overridden with defaults. + */ + $props = wp_parse_args( $props, $this->get_default_label_props( $shipment ) ); + + foreach ( $props as $key => $value ) { + if ( substr( $key, 0, strlen( 'service_' ) ) === 'service_' ) { + $new_key = substr( $key, ( strlen( 'service_' ) ) ); + + if ( wc_string_to_bool( $value ) && in_array( $new_key, $this->get_available_label_services( $shipment ), true ) ) { + if ( ! in_array( $new_key, $props['services'], true ) ) { + $props['services'][] = $new_key; + } + unset( $props[ $key ] ); + } else { + if ( ( $service_key = array_search( $new_key, $props['services'], true ) ) !== false ) { + unset( $props['services'][ $service_key ] ); + } + unset( $props[ $key ] ); + } + } + } + } + + $props = $this->validate_label_request( $shipment, $props ); + + if ( is_wp_error( $props ) ) { + return $props; + } + + if ( isset( $props['services'] ) ) { + $props['services'] = array_unique( $props['services'] ); + } + + $label = Factory::get_label( 0, $this->get_name(), $shipment->get_type() ); + + if ( $label ) { + foreach ( $props as $key => $value ) { + $setter = "set_{$key}"; + + if ( is_callable( array( $label, $setter ) ) ) { + $label->{$setter}( $value ); + } else { + $label->update_meta_data( $key, $value ); + } + } + + $label->set_shipment( $shipment ); + + /** + * Fetch the label via API and store as file + */ + $result = $label->fetch(); + + if ( is_wp_error( $result ) ) { + return $result; + } else { + do_action( "{$this->get_general_hook_prefix()}created_label", $label, $this ); + + return $label->save(); + } + } + + return new \WP_Error( 'label-error', _x( 'Error while creating the label.', 'shipments', 'woocommerce-germanized' ) ); + } + + /** + * @param \Vendidero\Germanized\Shipments\Shipment $shipment + */ + public function get_available_label_services( $shipment ) { + return array(); + } + + /** + * @param \Vendidero\Germanized\Shipments\Shipment $shipment + */ + abstract public function get_available_label_products( $shipment ); + + /** + * @param \Vendidero\Germanized\Shipments\Shipment $shipment + */ + abstract public function get_default_label_product( $shipment ); +} diff --git a/packages/woocommerce-germanized-shipments/src/ShippingProvider/Helper.php b/packages/woocommerce-germanized-shipments/src/ShippingProvider/Helper.php new file mode 100644 index 000000000..3a7f81445 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/ShippingProvider/Helper.php @@ -0,0 +1,202 @@ +get_shipping_provider_class_names(); + + if ( ! is_object( $provider ) ) { + if ( ! class_exists( $provider ) ) { + return false; + } + + $provider = new $provider(); + } else { + $classname = '\Vendidero\Germanized\Shipments\ShippingProvider\Simple'; + + if ( array_key_exists( $provider->shipping_provider_name, $classes ) ) { + $classname = $classes[ $provider->shipping_provider_name ]; + } + + $classname = apply_filters( 'woocommerce_gzd_shipping_provider_class_name', $classname, $provider->shipping_provider_name, $provider ); + + if ( ! class_exists( $classname ) ) { + $classname = '\Vendidero\Germanized\Shipments\ShippingProvider\Simple'; + } + + $provider = new $classname( $provider ); + } + + if ( ! $provider || ! is_a( $provider, '\Vendidero\Germanized\Shipments\Interfaces\ShippingProvider' ) ) { + return false; + } + + if ( is_null( $this->shipping_providers ) ) { + $this->shipping_providers = array(); + } + + $this->shipping_providers[ $provider->get_name() ] = $provider; + } + + /** + * Shipping providers register themselves by returning their main class name through the woocommerce_gzd_shipping_provider_integrations filter. + * + * @return array + */ + public function get_shipping_provider_class_names() { + $class_names = array(); + + /** + * This filter may be used to register additional shipping providers + * by adding a unique name as key and the classname to be loaded as value of the array. + * + * @param array $shipping_providers The shipping provider array + * + * @since 1.0.5 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipping_provider_class_names', $class_names ); + } + + public function is_shipping_provider_activated( $name ) { + /** + * Make sure that the plugin has initialised, e.g. during installs of shipping provider + */ + if ( ! did_action( 'woocommerce_gzd_shipments_init' ) ) { + Package::init(); + } + + return WC_Data_Store::load( 'shipping-provider' )->is_activated( $name ); + } + + /** + * Loads all shipping providers which are hooked in. + * + * @return ShippingProvider[] + */ + public function load_shipping_providers() { + $this->shipping_providers = array(); + + // Unique provider name => provider class name. + $shipping_providers = array_merge( $this->get_shipping_provider_class_names(), WC_Data_Store::load( 'shipping-provider' )->get_shipping_providers() ); + + // For the settings in the backend, and for non-shipping zone methods, we still need to load any registered classes here. + foreach ( $shipping_providers as $provider_name => $provider_class ) { + $this->register_shipping_provider( $provider_class ); + } + + /** + * This hook fires as soon as shipping providers are loaded. + * Additional shipping provider may be registered manually afterwards. + * + * @param Helper $providers The shipping providers instance + * + * @since 3.0.6 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_load_shipping_providers', $this ); + + // Return loaded methods. + return $this->get_shipping_providers(); + } + + /** + * Returns all registered shipping providers for usage. + * + * @return Simple|Auto|ShippingProvider[] + */ + public function get_shipping_providers() { + if ( is_null( $this->shipping_providers ) ) { + $this->load_shipping_providers(); + } + + return $this->shipping_providers; + } + + /** + * @param $name + * + * @return false|Simple|Auto|ShippingProvider + */ + public function get_shipping_provider( $name ) { + $providers = $this->get_shipping_providers(); + + return ( array_key_exists( $name, $providers ) ? $providers[ $name ] : false ); + } +} diff --git a/packages/woocommerce-germanized-shipments/src/ShippingProvider/Method.php b/packages/woocommerce-germanized-shipments/src/ShippingProvider/Method.php new file mode 100644 index 000000000..35a60f05d --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/ShippingProvider/Method.php @@ -0,0 +1,414 @@ +method = $method; + $this->init(); + } else { + $this->is_placeholder = true; + $this->init_placeholder( $method ); + } + } + + protected function init_placeholder( $id ) { + if ( is_a( $id, 'WC_Shipping_Rate' ) ) { + $instance_id = $id->get_instance_id(); + $id = $id->get_id(); + + if ( strpos( $id, ':' ) === false ) { + $id = $id . ':' . $instance_id; + } + } elseif ( is_a( $id, 'WC_Shipping_Method' ) ) { + $instance_id = $id->get_instance_id(); + $id = $id->id; + + if ( strpos( $id, ':' ) === false ) { + $id = $id . ':' . $instance_id; + } + } + + if ( ! is_numeric( $id ) ) { + $expl = explode( ':', $id ); + $instance_id = ( ( ! empty( $expl ) && count( $expl ) > 1 ) ? $expl[1] : 0 ); + $id = ( ( ! empty( $expl ) && count( $expl ) > 1 ) ? $expl[0] : $id ); + } else { + $instance_id = $id; + } + + $this->placeholder_id = $id; + $this->placeholder_instance_id = $instance_id; + + $this->instance_form_fields = Package::get_method_settings(); + } + + public function get_fallback_setting_value( $setting_key ) { + $setting_key = $this->maybe_prefix_key( $setting_key ); + $setting_value = ''; + + /** + * In case the setting belongs to the current shipping provider + * lets allow overriding the fallback setting with data from the provider. + */ + if ( ( $provider = $this->get_provider_instance() ) && $this->setting_belongs_to_provider( $setting_key ) ) { + $setting_value = $provider->get_setting( $setting_key ); + } + + if ( is_null( $setting_value ) ) { + $setting_value = Package::get_setting( $setting_key, null ); + } + + /** + * Convert booleans to string options + */ + if ( is_bool( $setting_value ) ) { + $setting_value = wc_bool_to_string( $setting_value ); + } + + return apply_filters( "{$this->get_hook_prefix()}setting_fallback_value", $setting_value, $setting_key, $this ); + } + + protected function supports_instance_settings() { + if ( $this->is_placeholder() ) { + return false; + } else { + $supports_settings = ( $this->method->supports( 'instance-settings' ) && $this->method->supports( 'instance-settings-modal' ) ) ? true : false; + + return apply_filters( 'woocommerce_gzd_shipping_provider_method_supports_instance_settings', $supports_settings, $this ); + } + } + + public function is_placeholder() { + return true === $this->is_placeholder; + } + + /** + * Get all available shipping method settings. This method (re-) loads all + * the settings available across every registered shipping provider. + * Call the cached version instead for performance improvements. + * + * @see Package::get_method_settings() + * + * @return mixed|void + */ + public static function get_admin_settings() { + /** + * Filter to adjust admin settings added to the shipment method instance specifically for shipping providers. + * + * @param array $settings Admin setting fields. + * + * @since 3.0.6 + * @package Vendidero/Germanized/Shipments + */ + $settings = apply_filters( + 'woocommerce_gzd_shipping_provider_method_admin_settings', + array( + 'shipping_provider_title' => array( + 'title' => _x( 'Shipping Provider Settings', 'shipments', 'woocommerce-germanized' ), + 'type' => 'title', + 'default' => '', + 'description' => _x( 'Adjust shipping provider settings used for managing shipments.', 'shipments', 'woocommerce-germanized' ), + ), + 'shipping_provider' => array( + 'title' => _x( 'Shipping Provider', 'shipments', 'woocommerce-germanized' ), + 'type' => 'select', + /** + * Filter to adjust default shipping provider pre-selected within shipping provider method settings. + * + * @param string $provider_name The shipping provider name e.g. dhl. + * + * @since 3.0.6 + * @package Vendidero/Germanized/Shipments + */ + 'default' => apply_filters( 'woocommerce_gzd_shipping_provider_method_default_provider', '' ), + 'options' => wc_gzd_get_shipping_provider_select(), + 'description' => _x( 'Choose a shipping provider which will be selected by default for an eligible shipment.', 'shipments', 'woocommerce-germanized' ), + ), + ) + ); + + foreach ( wc_gzd_get_shipping_providers() as $provider ) { + if ( ! $provider->is_activated() ) { + continue; + } + + $additional_settings = $provider->get_shipping_method_settings(); + $settings = array_merge( $settings, $additional_settings ); + } + + /** + * Append a stop title to make sure the table is closed within settings. + */ + $settings = array_merge( + $settings, + array( + 'shipping_provider_stop_title' => array( + 'title' => '', + 'type' => 'title', + 'default' => '', + ), + ) + ); + + return apply_filters( 'woocommerce_gzd_shipping_provider_method_admin_settings_wrapped', $settings ); + } + + protected function init() { + $this->instance_form_fields = Package::get_method_settings(); + + if ( ! array_key_exists( 'shipping_provider', $this->get_method()->instance_form_fields ) ) { + $this->get_method()->instance_form_fields = array_merge( $this->get_method()->instance_form_fields, $this->instance_form_fields ); + } + + // Refresh instance settings in case they were already loaded + if ( ! empty( $this->get_method()->instance_settings ) ) { + $this->get_method()->init_instance_settings(); + } + } + + protected function get_hook_prefix() { + $prefix = 'woocommerce_gzd_shipping_provider_method_'; + + return $prefix; + } + + /** + * Returns the Woo WC_Shipping_Method original object + * + * @return object|WC_Shipping_Method + */ + public function get_method() { + return $this->method; + } + + public function get_id() { + if ( ! $this->is_placeholder() ) { + return $this->method->id; + } else { + return $this->placeholder_id; + } + } + + public function get_instance_id() { + if ( ! $this->is_placeholder() ) { + return $this->method->get_instance_id(); + } else { + return $this->placeholder_instance_id; + } + } + + public function has_option( $key ) { + $fields = $this->instance_form_fields; + $key = $this->maybe_prefix_key( $key ); + $has_option = ( array_key_exists( $key, $fields ) && $this->setting_belongs_to_provider( $key ) ) ? true : false; + + /** + * Filter that allows checking whether a shipping provider method has a specific option or not. + * + * @param boolean $has_option Whether or not the option exists. + * @param string $key The setting key. + * @param Method $method The method instance. + * + * @since 3.0.6 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( "{$this->get_hook_prefix()}setting_prefix", $has_option, $key, $this ); + } + + public function setting_belongs_to_provider( $setting_key, $provider = '' ) { + $prefix = $this->get_custom_setting_prefix_key(); + + if ( ! empty( $provider ) ) { + $prefix = $provider . '_'; + } + + $belongs_to_provider = false; + + if ( ! empty( $prefix ) && substr( $setting_key, 0, strlen( $prefix ) ) === $prefix ) { + $belongs_to_provider = true; + } + + return $belongs_to_provider; + } + + public function is_provider_enabled( $provider ) { + return ( $this->get_provider() === $provider ) ? true : false; + } + + public function set_provider( $provider_name ) { + $this->provider_slug = $provider_name; + } + + public function get_provider() { + $id = sanitize_key( $this->get_id() ); + + if ( is_null( $this->provider_slug ) ) { + $provider_slug = $this->method ? $this->method->get_option( 'shipping_provider' ) : ''; + + if ( ! empty( $provider_slug ) ) { + if ( $provider = wc_gzd_get_shipping_provider( $provider_slug ) ) { + + if ( ! $provider->is_activated() ) { + $provider_slug = ''; + } + } + } + + if ( empty( $provider_slug ) ) { + $provider_slug = wc_gzd_get_default_shipping_provider(); + } + + /** + * Filter that allows adjusting the shipping provider chosen for a specific shipping method. + * + * @param string $provider_slug The shipping provider. + * @param string $method_id The shipping method id. + * @param Method $method The method instance. + * + * @since 3.0.6 + * @package Vendidero/Germanized/Shipments + */ + $this->provider_slug = apply_filters( 'woocommerce_gzd_shipping_provider_method_provider', $provider_slug, $this->get_id(), $this ); + } + + /** + * Filter that allows choosing a shipping provider for a specific shipping method. + * + * The dynamic portion of this hook, `$id` refers to the shipping method id. + * + * Example hook name: `woocommerce_gzd_shipping_provider_method_flat_rate_provider` + * + * @param string $provider_slug The shipping provider name to be used. + * @param Method $method The method instance. + * + * @since 3.0.6 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( "{$this->get_hook_prefix()}{$id}_provider", $this->provider_slug, $this ); + } + + public function get_provider_instance() { + $provider_slug = $this->get_provider(); + + if ( ! empty( $provider_slug ) ) { + return wc_gzd_get_shipping_provider( $provider_slug ); + } + + return false; + } + + protected function get_custom_setting_prefix_key() { + $prefix = ''; + + if ( $provider = $this->get_provider_instance() ) { + $prefix = $provider->get_name() . '_'; + } + + return apply_filters( "{$this->get_hook_prefix()}custom_setting_prefix", $prefix, $this ); + } + + protected function maybe_prefix_key( $key ) { + $fields = $this->instance_form_fields; + $prefix = $this->get_custom_setting_prefix_key(); + $new_key = $key; + + // Do only prefix if the prefix does not yet exist. + if ( ! array_key_exists( $new_key, $fields ) ) { + if ( substr( $key, 0, strlen( $prefix ) ) !== $prefix ) { + $new_key = $prefix . $key; + } + } + + /** + * Filter that allows prefixing the setting key used for a shipping provider method. + * + * @param string $new_key The prefixed setting key. + * @param string $key The original setting key. + * @param Method $method The method instance. + * + * @since 3.0.6 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( "{$this->get_hook_prefix()}setting_key_prefixed", $new_key, $key, $this ); + } + + public function get_option( $key ) { + $key = $this->maybe_prefix_key( $key ); + $option_value = $this->get_fallback_setting_value( $key ); + + if ( ! $this->is_placeholder() ) { + if ( $this->has_option( $key ) && $this->supports_instance_settings() ) { + $option_type = isset( $this->instance_form_fields[ $key ]['type'] ) ? $this->instance_form_fields[ $key ]['type'] : 'text'; + + // Do only use method settings if the method is not a placeholder and method supports settings + $option_value = $this->method->get_option( $key, $option_value ); + + if ( in_array( $option_type, array( 'checkbox', 'radio' ), true ) ) { + $option_value = wc_string_to_bool( $option_value ); + + if ( $option_value ) { + $option_value = 'yes'; + } else { + $option_value = 'no'; + } + } + } + } + + return apply_filters( "{$this->get_hook_prefix()}setting_value", $option_value, $key, $this ); + } + + /** + * Call child methods if the method does not exist. + * + * @param $method + * @param $args + * + * @return bool|mixed + */ + public function __call( $method, $args ) { + + if ( method_exists( $this->method, $method ) ) { + return call_user_func_array( array( $this->method, $method ), $args ); + } + + return false; + } +} diff --git a/packages/woocommerce-germanized-shipments/src/ShippingProvider/MethodPlaceholder.php b/packages/woocommerce-germanized-shipments/src/ShippingProvider/MethodPlaceholder.php new file mode 100644 index 000000000..d4ee5aaf7 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/ShippingProvider/MethodPlaceholder.php @@ -0,0 +1,25 @@ + true, + 'title' => '', + 'name' => '', + 'description' => '', + 'supports_customer_returns' => false, + 'supports_guest_returns' => false, + 'return_manual_confirmation' => true, + 'return_instructions' => '', + 'tracking_url_placeholder' => '', + 'tracking_desc_placeholder' => '', + ); + + protected $address_data = array( + 'shipper' => null, + 'return' => null, + ); + + /** + * Get the provider if ID is passed. In case it is an integration, data will be provided through the impl. + * This class should NOT be instantiated, but the `wc_gzd_get_shipping_provider` function should be used. + * + * @param int|object|ShippingProvider $provider Provider to read. + */ + public function __construct( $data = 0 ) { + parent::__construct( $data ); + + if ( $data instanceof ShippingProvider ) { + $this->set_id( absint( $data->get_id() ) ); + } elseif ( is_numeric( $data ) ) { + $this->set_id( $data ); + } elseif ( is_object( $data ) && isset( $data->shipping_provider_id ) ) { + $this->set_id( $data->shipping_provider_id ); + } + + $this->data_store = WC_Data_Store::load( $this->data_store_name ); + + // If we have an ID, load the user from the DB. + if ( $this->get_id() ) { + try { + $this->data_store->read( $this ); + } catch ( Exception $e ) { + $this->set_id( 0 ); + $this->set_object_read( true ); + } + } else { + $this->set_object_read( true ); + } + } + + public function get_help_link() { + return ''; + } + + public function get_signup_link() { + return ''; + } + + public function is_pro() { + return false; + } + + /** + * Whether or not this instance is a manual integration. + * Manual integrations are constructed dynamically from DB and do not support + * automatic shipment handling, e.g. label creation. + * + * @return bool + */ + public function is_manual_integration() { + return true; + } + + /** + * Whether or not this instance supports a certain label type. + * + * @param string $label_type The label type e.g. simple or return. + * @param false|Shipment Shipment instance + * + * @return bool + */ + public function supports_labels( $label_type, $shipment = false ) { + return false; + } + + public function supports_customer_return_requests() { + if ( $this->is_manual_integration() ) { + return true; + } + + return false; + } + + /** + * Some providers (e.g. DHL) create return labels automatically and the return + * address is chosen dynamically depending on the country. For that reason the return address + * might not show up within emails or in customer panel. + * + * @return bool + */ + public function hide_return_address() { + return false; + } + + public function get_edit_link( $section = '' ) { + $url = admin_url( 'admin.php?page=wc-settings&tab=germanized-shipping_provider&provider=' . esc_attr( $this->get_name() ) ); + $url = add_query_arg( array( 'section' => $section ), $url ); + + return esc_url_raw( $url ); + } + + /** + * Returns whether the shipping provider is active for usage or not. + * + * @return bool + */ + public function is_activated() { + return $this->get_activated() === true; + } + + public function needs_manual_confirmation_for_returns() { + return $this->get_return_manual_confirmation() === true; + } + + /** + * @param false|\WC_Order $order + * + * @return bool + */ + public function supports_customer_returns( $order = false ) { + return $this->get_supports_customer_returns() === true; + } + + public function supports_guest_returns() { + return $this->get_supports_customer_returns() === true && $this->get_supports_guest_returns() === true; + } + + /** + * Returns a title for the shipping provider. + * + * @param string $context + * + * @return string + */ + public function get_title( $context = 'view' ) { + return $this->get_prop( 'title', $context ); + } + + /** + * Returns a unique slug/name for the shipping provider. + * + * @param string $context + * + * @return string + */ + public function get_name( $context = 'view' ) { + return $this->get_prop( 'name', $context ); + } + + /** + * Returns a description for the provider. + * + * @param string $context + * + * @return string + */ + public function get_description( $context = 'view' ) { + $desc = $this->get_prop( 'description', $context ); + + if ( 'view' === $context && empty( $desc ) ) { + return '-'; + } + + return $desc; + } + + /** + * Returns whether the shipping provider is activated or not. + * + * @param string $context + * + * @return string + */ + public function get_activated( $context = 'view' ) { + return $this->get_prop( 'activated', $context ); + } + + /** + * Returns whether the shipping provider needs manual confirmation for a return. + * + * @param string $context + * + * @return string + */ + public function get_return_manual_confirmation( $context = 'view' ) { + return $this->get_prop( 'return_manual_confirmation', $context ); + } + + /** + * Returns whether the shipping provider supports returns added by customers or not. + * + * @param string $context + * + * @return string + */ + public function get_supports_customer_returns( $context = 'view' ) { + return $this->get_prop( 'supports_customer_returns', $context ); + } + + /** + * Returns whether the shipping provider supports returns added by guests or not. + * + * @param string $context + * + * @return string + */ + public function get_supports_guest_returns( $context = 'view' ) { + return $this->get_prop( 'supports_guest_returns', $context ); + } + + /** + * Returns the tracking url placeholder which is being used to + * construct a tracking url. + * + * @param string $context + * + * @return mixed + */ + public function get_tracking_url_placeholder( $context = 'view' ) { + $data = $this->get_prop( 'tracking_url_placeholder', $context ); + + // In case the option value is not stored in DB yet + if ( 'view' === $context && empty( $data ) ) { + $data = $this->get_default_tracking_url_placeholder(); + } + + return $data; + } + + public function get_default_tracking_url_placeholder() { + return ''; + } + + /** + * Returns the tracking description placeholder which is being used to + * construct a tracking description. + * + * @param string $context + * + * @return mixed + */ + public function get_tracking_desc_placeholder( $context = 'view' ) { + $data = $this->get_prop( 'tracking_desc_placeholder', $context ); + + // In case the option value is not stored in DB yet + if ( 'view' === $context && empty( $data ) ) { + $data = $this->get_default_tracking_desc_placeholder(); + } + + return $data; + } + + public function get_default_tracking_desc_placeholder() { + return _x( 'Your shipment is being processed by {shipping_provider}. If you want to track the shipment, please use the following tracking number: {tracking_id}. Depending on the chosen shipping method it is possible that the tracking data does not reflect the current status when receiving this email.', 'shipments', 'woocommerce-germanized' ); + } + + /** + * Returns the return instructions. + * + * @param string $context + * + * @return mixed + */ + public function get_return_instructions( $context = 'view' ) { + return $this->get_prop( 'return_instructions', $context ); + } + + public function has_return_instructions() { + $instructions = $this->get_return_instructions(); + + return empty( $instructions ) ? false : true; + } + + protected function get_address_props( $address_type = 'shipper' ) { + if ( is_null( $this->address_data[ $address_type ] ) ) { + $this->address_data[ $address_type ] = wc_gzd_get_shipment_setting_address_fields( $address_type ); + } + + return $this->address_data[ $address_type ]; + } + + public function get_shipper_address_data() { + return $this->get_address_props( 'shipper' ); + } + + public function get_address_prop( $prop, $type = 'shipper' ) { + $address_fields = $this->get_address_props( $type ); + + return array_key_exists( $prop, $address_fields ) ? $address_fields[ $prop ] : ''; + } + + public function get_shipper_email() { + return $this->get_address_prop( 'email' ); + } + + public function get_shipper_phone() { + return $this->get_address_prop( 'phone' ); + } + + public function get_contact_phone() { + return get_option( 'woocommerce_gzd_shipments_contact_phone' ); + } + + public function get_shipper_first_name() { + return $this->get_address_prop( 'first_name' ); + } + + public function get_shipper_last_name() { + return $this->get_address_prop( 'last_name' ); + } + + public function get_shipper_name() { + return $this->get_shipper_formatted_full_name(); + } + + public function get_shipper_formatted_full_name() { + return $this->get_address_prop( 'full_name' ); + } + + public function get_shipper_company() { + return $this->get_address_prop( 'company' ); + } + + public function get_shipper_address() { + return $this->get_address_prop( 'address_1' ); + } + + public function get_shipper_address_1() { + return $this->get_shipper_address(); + } + + public function get_shipper_address_2() { + return $this->get_address_prop( 'address_2' ); + } + + public function get_shipper_street() { + return $this->get_address_prop( 'street' ); + } + + public function get_shipper_street_number() { + return $this->get_address_prop( 'street_number' ); + } + + public function get_shipper_postcode() { + return $this->get_address_prop( 'postcode' ); + } + + public function get_shipper_city() { + return $this->get_address_prop( 'city' ); + } + + public function get_shipper_customs_reference_number() { + return $this->get_address_prop( 'customs_reference_number' ); + } + + public function get_shipper_country() { + $country_data = wc_format_country_state_string( $this->get_address_prop( 'country' ) ); + + return $country_data['country']; + } + + public function get_shipper_state() { + $country_data = wc_format_country_state_string( $this->get_address_prop( 'country' ) ); + + return $country_data['state']; + } + + public function get_return_address_data() { + return $this->get_address_props( 'return' ); + } + + public function get_return_first_name() { + return $this->get_address_prop( 'first_name', 'return' ); + } + + public function get_return_last_name() { + return $this->get_address_prop( 'last_name', 'return' ); + } + + public function get_return_company() { + return $this->get_address_prop( 'company', 'return' ); + } + + public function get_return_name() { + return $this->get_return_formatted_full_name(); + } + + public function get_return_formatted_full_name() { + return $this->get_address_prop( 'full_name', 'return' ); + } + + public function get_return_address() { + return $this->get_address_prop( 'address_1', 'return' ); + } + + public function get_return_address_2() { + return $this->get_address_prop( 'address_2', 'return' ); + } + + public function get_return_street() { + return $this->get_address_prop( 'street', 'return' ); + } + + public function get_return_street_number() { + return $this->get_address_prop( 'street_number', 'return' ); + } + + public function get_return_postcode() { + return $this->get_address_prop( 'postcode', 'return' ); + } + + public function get_return_city() { + return $this->get_address_prop( 'city', 'return' ); + } + + public function get_return_country() { + $country_data = wc_format_country_state_string( $this->get_address_prop( 'country', 'return' ) ); + + return $country_data['country']; + } + + public function get_return_state() { + $country_data = wc_format_country_state_string( $this->get_address_prop( 'country', 'return' ) ); + + return $country_data['state']; + } + + public function get_return_email() { + return $this->get_address_prop( 'email', 'return' ); + } + + public function get_return_phone() { + return $this->get_address_prop( 'phone', 'return' ); + } + + /** + * Set the current shipping provider to active or inactive. + * + * @param bool $is_activated + */ + public function set_activated( $is_activated ) { + $this->set_prop( 'activated', wc_string_to_bool( $is_activated ) ); + } + + /** + * Mark the current shipping provider as manual needed confirmation for returns. + * + * @param bool $needs_confirmation + */ + public function set_return_manual_confirmation( $needs_confirmation ) { + $this->set_prop( 'return_manual_confirmation', wc_string_to_bool( $needs_confirmation ) ); + } + + /** + * Set whether or not the current shipping provider supports customer returns + * + * @param bool $supports + */ + public function set_supports_customer_returns( $supports ) { + $this->set_prop( 'supports_customer_returns', wc_string_to_bool( $supports ) ); + } + + /** + * Set whether or not the current shipping provider supports guest returns + * + * @param bool $supports + */ + public function set_supports_guest_returns( $supports ) { + $this->set_prop( 'supports_guest_returns', wc_string_to_bool( $supports ) ); + } + + public function update_settings_with_defaults() { + foreach ( $this->get_all_settings() as $section => $settings ) { + foreach ( $settings as $setting ) { + $type = isset( $setting['type'] ) ? $setting['type'] : 'title'; + $default = isset( $setting['default'] ) ? $setting['default'] : null; + + if ( in_array( $type, array( 'title', 'sectionend', 'html' ), true ) || ! isset( $setting['id'] ) || empty( $setting['id'] ) ) { + continue; + } + + $current_value = $this->get_setting( $setting['id'], null, 'edit' ); + + /** + * Update meta data with default value in case it does not yet exist. + */ + if ( is_null( $current_value ) && ! is_null( $default ) ) { + $this->update_setting( $setting['id'], $default ); + } + } + } + } + + /** + * Activate current ShippingProvider instance. + */ + public function activate() { + $this->set_activated( true ); + $this->update_settings_with_defaults(); + $this->save(); + + /** + * This action fires as soon as a certain shipping provider gets activated. + * + * @param ShippingProvider $shipping_provider The shipping provider instance. + */ + do_action( 'woocommerce_gzd_shipping_provider_activated', $this ); + } + + /** + * Deactivate current ShippingProvider instance. + */ + public function deactivate() { + $this->set_activated( false ); + $this->save(); + + /** + * This action fires as soon as a certain shipping provider gets deactivated. + * + * @param ShippingProvider $shipping_provider The shipping provider instance. + */ + do_action( 'woocommerce_gzd_shipping_provider_deactivated', $this ); + } + + /** + * Set the name of the current shipping provider. + * + * @param string $name + */ + public function set_name( $name ) { + $this->set_prop( 'name', $name ); + } + + /** + * Set the title of the current shipping provider. + * + * @param string $title + */ + public function set_title( $title ) { + $this->set_prop( 'title', $title ); + } + + /** + * Set the description of the current shipping provider. + * + * @param string $description + */ + public function set_description( $description ) { + $this->set_prop( 'description', $description ); + } + + /** + * Set the return instructions of the current shipping provider. + * + * @param string $instructions + */ + public function set_return_instructions( $instructions ) { + $this->set_prop( 'return_instructions', $instructions ); + } + + /** + * Set the tracking url placeholder of the current shipping provider. + * + * @param string $placeholder + */ + public function set_tracking_url_placeholder( $placeholder ) { + $this->set_prop( 'tracking_url_placeholder', $placeholder ); + } + + /** + * Set the tracking description placeholder of the current shipping provider. + * + * @param string $placeholder + */ + public function set_tracking_desc_placeholder( $placeholder ) { + $this->set_prop( 'tracking_desc_placeholder', $placeholder ); + } + + /** + * Returns the tracking url for a specific shipment. + * + * @param Shipment $shipment + * + * @return string + */ + public function get_tracking_url( $shipment ) { + + $tracking_url = ''; + $tracking_id = $shipment->get_tracking_id(); + + if ( '' !== $this->get_tracking_url_placeholder() && ! empty( $tracking_id ) ) { + $placeholders = $this->get_tracking_placeholders( $shipment ); + $tracking_url = str_replace( array_keys( $placeholders ), array_values( $placeholders ), $this->get_tracking_url_placeholder() ); + } + + /** + * This filter returns the tracking url provided by the shipping provider for a certain shipment. + * + * The dynamic portion of the hook `$this->get_hook_prefix()` refers to the + * current provider name. + * + * Example hook name: woocommerce_gzd_shipping_provider_dhl_get_tracking_url + * + * @param string $tracking_url The tracking url. + * @param Shipment $shipment The shipment used to build the url. + * @param ShippingProvider $provider The shipping provider. + * + * @since 3.0.6 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( $this->get_hook_prefix() . 'tracking_url', $tracking_url, $shipment, $this ); + } + + /** + * Returns the tracking description for a certain shipment. + * + * @param Shipment $shipment + * + * @return string + */ + public function get_tracking_desc( $shipment, $plain = false ) { + $tracking_desc = ''; + $tracking_id = $shipment->get_tracking_id(); + + if ( '' !== $this->get_tracking_desc_placeholder() && ! empty( $tracking_id ) ) { + $placeholders = $this->get_tracking_placeholders( $shipment ); + + if ( ! $plain && apply_filters( "{$this->get_general_hook_prefix()}tracking_id_with_link", true, $shipment ) && $shipment->has_tracking() ) { + $placeholders['{tracking_id}'] = '' . $shipment->get_tracking_id() . ''; + } + + $tracking_desc = str_replace( array_keys( $placeholders ), array_values( $placeholders ), $this->get_tracking_desc_placeholder() ); + } + + /** + * This filter returns the tracking description provided by the shipping provider for a certain shipment. + * + * The dynamic portion of the hook `$this->get_hook_prefix()` refers to the + * current provider name. + * + * Example hook name: woocommerce_gzd_shipping_provider_dhl_get_tracking_description + * + * @param string $tracking_url The tracking description. + * @param Shipment $shipment The shipment used to build the url. + * @param ShippingProvider $provider The shipping provider. + * + * @since 3.0.6 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( $this->get_hook_prefix() . 'tracking_desc', $tracking_desc, $shipment, $this ); + } + + /** + * @param bool|Shipment $shipment + * + * @return array + */ + public function get_tracking_placeholders( $shipment = false ) { + $label = false; + + if ( $shipment ) { + $label = $shipment->get_label(); + } + + /** + * This filter may be used to add or manipulate tracking placeholder data + * for a certain shipping provider. + * + * The dynamic portion of the hook `$this->get_hook_prefix()` refers to the + * current provider name. + * + * Example hook name: woocommerce_gzd_shipping_provider_dhl_get_tracking_placeholders + * + * @param array $placeholders Placeholders in key => value pairs. + * @param ShippingProvider $provider The shipping provider. + * @param Shipment|bool $shipment The shipment instance if available. + * + * @since 3.0.6 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( + "{$this->get_hook_prefix()}tracking_placeholders", + array( + '{shipment_number}' => $shipment ? $shipment->get_shipment_number() : '', + '{order_number}' => $shipment ? $shipment->get_order_number() : '', + '{tracking_id}' => $shipment ? $shipment->get_tracking_id() : '', + '{postcode}' => $shipment ? $shipment->get_postcode() : '', + '{date_sent_day}' => $shipment && $shipment->get_date_sent() ? $shipment->get_date_sent()->format( 'd' ) : '', + '{date_sent_month}' => $shipment && $shipment->get_date_sent() ? $shipment->get_date_sent()->format( 'm' ) : '', + '{date_sent_year}' => $shipment && $shipment->get_date_sent() ? $shipment->get_date_sent()->format( 'Y' ) : '', + '{date_day}' => $shipment && $shipment->get_date_created() ? $shipment->get_date_created()->format( 'd' ) : '', + '{date_month}' => $shipment && $shipment->get_date_created() ? $shipment->get_date_created()->format( 'm' ) : '', + '{date_year}' => $shipment && $shipment->get_date_created() ? $shipment->get_date_created()->format( 'Y' ) : '', + '{label_date_day}' => $label ? $label->get_date_created()->format( 'd' ) : '', + '{label_date_month}' => $label ? $label->get_date_created()->format( 'm' ) : '', + '{label_date_year}' => $label ? $label->get_date_created()->format( 'Y' ) : '', + '{shipping_provider}' => $this->get_title(), + ), + $this, + $shipment + ); + } + + /** + * Prefix for action and filter hooks on data. + * + * @since 3.0.0 + * @return string + */ + protected function get_hook_prefix() { + return $this->get_general_hook_prefix() . 'get_'; + } + + /** + * Prefix for action and filter hooks on data. + * + * @since 3.0.0 + * @return string + */ + protected function get_general_hook_prefix() { + $name = sanitize_key( $this->get_name( 'edit' ) ); + + if ( empty( $name ) ) { + return 'woocommerce_gzd_shipping_provider_'; + } else { + return "woocommerce_gzd_shipping_provider_{$name}_"; + } + } + + protected function get_general_settings( $for_shipping_method = false ) { + $settings = array( + array( + 'title' => '', + 'type' => 'title', + 'id' => 'shipping_provider_options', + ), + ); + + if ( $this->is_manual_integration() ) { + $settings = array_merge( + $settings, + array( + array( + 'title' => _x( 'Title', 'shipments', 'woocommerce-germanized' ), + 'desc_tip' => _x( 'Choose a title for the shipping provider.', 'shipments', 'woocommerce-germanized' ), + 'id' => 'shipping_provider_title', + 'value' => $this->get_title( 'edit' ), + 'default' => '', + 'type' => 'text', + ), + + array( + 'title' => _x( 'Description', 'shipments', 'woocommerce-germanized' ), + 'desc_tip' => _x( 'Choose a description for the shipping provider.', 'shipments', 'woocommerce-germanized' ), + 'id' => 'shipping_provider_description', + 'value' => $this->get_description( 'edit' ), + 'default' => '', + 'type' => 'textarea', + 'css' => 'width: 100%;', + ), + ) + ); + } + + $settings = array_merge( + $settings, + array( + array( + 'title' => _x( 'Tracking URL', 'shipments', 'woocommerce-germanized' ), + 'desc' => '
' . sprintf( _x( 'Adjust the placeholder used to construct the tracking URL for this shipping provider. You may use on of the following placeholders to insert the tracking id or other dynamic data: %s', 'shipments', 'woocommerce-germanized' ), '' . implode( ', ', array_keys( $this->get_tracking_placeholders() ) ) . '' ) . '
', + 'id' => 'shipping_provider_tracking_url_placeholder', + 'placeholder' => $this->get_default_tracking_url_placeholder(), + 'value' => $this->get_tracking_url_placeholder( 'edit' ), + 'default' => $this->get_default_tracking_url_placeholder(), + 'type' => 'text', + 'css' => 'width: 100%;', + ), + + array( + 'title' => _x( 'Tracking description', 'shipments', 'woocommerce-germanized' ), + 'desc' => '
' . sprintf( _x( 'Adjust the placeholder used to construct the tracking description for this shipping provider (e.g. used within notification emails). You may use on of the following placeholders to insert the tracking id or other dynamic data: %s', 'shipments', 'woocommerce-germanized' ), '' . implode( ', ', array_keys( $this->get_tracking_placeholders() ) ) . '' ) . '
', + 'id' => 'shipping_provider_tracking_desc_placeholder', + 'placeholder' => $this->get_default_tracking_desc_placeholder(), + 'value' => $this->get_tracking_desc_placeholder( 'edit' ), + 'default' => $this->get_default_tracking_desc_placeholder(), + 'type' => 'textarea', + 'css' => 'width: 100%; min-height: 60px; margin-top: 1em;', + ), + ) + ); + + $settings = array_merge( + $settings, + array( + array( + 'type' => 'sectionend', + 'id' => 'shipping_provider_options', + ), + ) + ); + + return $settings; + } + + /** + * @param Shipment $shipment + * @param $key + */ + public function get_shipment_setting( $shipment, $key, $default = null ) { + $value = $this->get_setting( $key, $default ); + + if ( $method = $shipment->get_shipping_method_instance() ) { + $prefixed_key = $this->get_name() . '_' . $key; + + if ( $method->has_option( $prefixed_key ) ) { + $method_value = $method->get_option( $prefixed_key ); + + if ( ! is_null( $method_value ) && $value !== $method_value ) { + $value = $method_value; + } + } + } + + return $value; + } + + public function get_setting( $key, $default = null, $context = 'view' ) { + $clean_key = $this->unprefix_setting_key( $key ); + $getter = "get_{$clean_key}"; + $value = $default; + + if ( is_callable( array( $this, $getter ) ) ) { + $value = $this->$getter( $context ); + } elseif ( $this->meta_exists( $clean_key ) ) { + $value = $this->get_meta( $clean_key, true, $context ); + } + + if ( strstr( $key, 'password' ) ) { + if ( class_exists( 'WC_GZD_Secret_Box_Helper' ) ) { + $result = \WC_GZD_Secret_Box_Helper::decrypt( $value ); + + if ( ! is_wp_error( $result ) ) { + $value = $result; + } + } + + $value = $this->retrieve_password( $value ); + } + + return $value; + } + + protected function retrieve_password( $value ) { + return stripslashes( $value ); + } + + protected function unprefix_setting_key( $key ) { + $prefixes = array( + 'shipping_provider_', + $this->get_name() . '_', + ); + + foreach ( $prefixes as $prefix ) { + if ( substr( $key, 0, strlen( $prefix ) ) === $prefix ) { + $key = substr( $key, strlen( $prefix ) ); + } + } + + return $key; + } + + public function update_settings( $section = '', $data = null, $save = true ) { + $settings_to_save = Settings::get_sanitized_settings( $this->get_settings( $section ), $data ); + + foreach ( $settings_to_save as $option_name => $value ) { + $this->update_setting( $option_name, $value ); + } + + if ( $save ) { + $this->save(); + } + } + + public function update_setting( $setting, $value ) { + $setting_name_clean = $this->unprefix_setting_key( $setting ); + $setter = 'set_' . $setting_name_clean; + + try { + if ( is_callable( array( $this, $setter ) ) ) { + $this->{$setter}( $value ); + } else { + $this->update_meta_data( $setting_name_clean, $value ); + } + } catch ( Exception $e ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch + } + } + + public function get_settings( $section = '', $for_shipping_method = false ) { + $settings = array(); + + if ( '' === $section || 'general' === $section ) { + $settings = $this->get_general_settings( $for_shipping_method ); + } elseif ( 'returns' === $section ) { + $settings = $this->get_return_settings( $for_shipping_method ); + } elseif ( is_callable( array( $this, "get_{$section}_settings" ) ) ) { + $settings = $this->{"get_{$section}_settings"}( $for_shipping_method ); + } + + /** + * This filter returns the admin settings available for a certain shipping provider. + * + * The dynamic portion of the hook `$this->get_hook_prefix()` refers to the + * current provider name. + * + * Example hook name: woocommerce_gzd_shipping_provider_dhl_get_settings + * + * @param array $settings Available settings. + * @param ShippingProvider $provider The shipping provider. + * + * @since 3.0.6 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( $this->get_hook_prefix() . 'settings', $settings, $section, $this, $for_shipping_method ); + } + + protected function get_return_settings( $for_shipping_method = false ) { + $settings = array( + array( + 'title' => '', + 'type' => 'title', + 'id' => 'shipping_provider_return_options', + ), + ); + + $settings = array_merge( + $settings, + array( + array( + 'title' => _x( 'Customer returns', 'shipments', 'woocommerce-germanized' ), + 'desc' => _x( 'Allow customers to submit return requests to shipments.', 'shipments', 'woocommerce-germanized' ) . '
' . sprintf( _x( 'This option will allow your customers to submit return requests to orders. Return requests will be visible within your %1$s. To learn more about return requests by customers and/or guests, please check the %2$s.', 'shipments', 'woocommerce-germanized' ), '' . _x( 'Return Dashboard', 'shipments', 'woocommerce-germanized' ) . '', '' . _x( 'docs', 'shipments', 'woocommerce-germanized' ) . '' ) . '
', + 'id' => 'supports_customer_returns', + 'placeholder' => '', + 'value' => wc_bool_to_string( $this->get_supports_customer_returns( 'edit' ) ), + 'default' => 'no', + 'type' => 'gzd_toggle', + ), + + array( + 'title' => _x( 'Guest returns', 'shipments', 'woocommerce-germanized' ), + 'desc' => _x( 'Allow guests to submit return requests to shipments.', 'shipments', 'woocommerce-germanized' ) . '
' . sprintf( _x( 'Guests will need to provide their email address and the order id to receive a one-time link to submit a return request. The placeholder %s might be used to place the request form on your site.', 'shipments', 'woocommerce-germanized' ), '[gzd_return_request_form]' ) . '
', + 'id' => 'supports_guest_returns', + 'default' => 'no', + 'value' => wc_bool_to_string( $this->get_supports_guest_returns( 'edit' ) ), + 'type' => 'gzd_toggle', + 'custom_attributes' => array( + 'data-show_if_shipping_provider_supports_customer_returns' => '', + ), + ), + + array( + 'title' => _x( 'Manual confirmation', 'shipments', 'woocommerce-germanized' ), + 'desc' => _x( 'Return requests need manual confirmation.', 'shipments', 'woocommerce-germanized' ) . '
' . _x( 'By default return request need manual confirmation e.g. a shop manager needs to review return requests which by default are added with the status "requested" after a customer submitted a return request. If you choose to disable this option, customer return requests will be added as "processing" and an email confirmation including instructions will be sent immediately to the customer.', 'shipments', 'woocommerce-germanized' ) . '
', + 'id' => 'return_manual_confirmation', + 'placeholder' => '', + 'value' => wc_bool_to_string( $this->get_return_manual_confirmation( 'edit' ) ), + 'default' => 'yes', + 'type' => 'gzd_toggle', + 'custom_attributes' => array( + 'data-show_if_shipping_provider_supports_customer_returns' => '', + ), + ), + + array( + 'title' => _x( 'Return instructions', 'shipments', 'woocommerce-germanized' ), + 'desc' => '
' . _x( 'Provide your customer with instructions on how to return the shipment after a return request has been confirmed e.g. explain how to prepare the return for shipment. In case a label cannot be generated automatically, make sure to provide your customer with information on how to obain a return label.', 'shipments', 'woocommerce-germanized' ) . '
', + 'id' => 'return_instructions', + 'placeholder' => '', + 'value' => $this->get_return_instructions( 'edit' ), + 'default' => '', + 'type' => 'textarea', + 'css' => 'width: 100%; min-height: 60px; margin-top: 1em;', + 'custom_attributes' => array( + 'data-show_if_shipping_provider_supports_customer_returns' => '', + ), + ), + ) + ); + + $settings = array_merge( + $settings, + array( + array( + 'type' => 'sectionend', + 'id' => 'shipping_provider_return_options', + ), + ) + ); + + return $settings; + } + + protected function get_all_settings( $for_shipping_method = false ) { + $settings = array(); + $sections = array_keys( $this->get_setting_sections() ); + + foreach ( $sections as $section ) { + $settings[ $section ] = $this->get_settings( $section, $for_shipping_method ); + } + + return $settings; + } + + public function get_shipping_method_settings() { + $settings = $this->get_all_settings( true ); + $sections = $this->get_setting_sections(); + + $method_settings = array(); + $include_current_section = false; + + foreach ( $settings as $section => $section_settings ) { + $global_settings_url = $this->get_edit_link( $section ); + $default_title = $sections[ $section ]; + + foreach ( $section_settings as $setting ) { + $include = false; + $setting = wp_parse_args( + $setting, + array( + 'allow_override' => ( $include_current_section && ! in_array( $setting['type'], array( 'title', 'sectionend' ), true ) ) ? true : false, + 'type' => '', + 'id' => '', + 'value' => '', + 'title_method' => '', + 'title' => '', + ) + ); + + if ( true === $setting['allow_override'] ) { + $include = true; + + if ( 'title' === $setting['type'] ) { + $include_current_section = true; + } + } elseif ( $include_current_section && ! in_array( $setting['type'], array( 'title', 'sectionend' ), true ) && false !== $setting['allow_override'] ) { + $include = true; + } elseif ( in_array( $setting['type'], array( 'title', 'sectionend' ), true ) ) { + $include_current_section = false; + } + + if ( $include ) { + $new_setting = array(); + $new_setting['id'] = $this->get_name() . '_' . $setting['id']; + $new_setting['type'] = str_replace( 'gzd_toggle', 'checkbox', $setting['type'] ); + $new_setting['default'] = $setting['value']; + + if ( 'checkbox' === $new_setting['type'] ) { + $new_setting['label'] = $setting['desc']; + } elseif ( isset( $setting['desc'] ) ) { + $new_setting['description'] = $setting['desc']; + } + + $copy = array( 'options', 'title', 'desc_tip' ); + + foreach ( $copy as $cp ) { + if ( isset( $setting[ $cp ] ) ) { + $new_setting[ $cp ] = $setting[ $cp ]; + } + } + + if ( 'title' === $new_setting['type'] ) { + $new_setting['description'] = sprintf( _x( 'These settings override your global %2$s options. Do only adjust these settings in case you would like to specifically adjust them for this specific shipping method.', 'shipments', 'woocommerce-germanized' ), esc_url( $global_settings_url ), $this->get_title() ); + + if ( empty( $setting['title'] ) ) { + $new_setting['title'] = $default_title; + } + + if ( ! empty( $setting['title_method'] ) ) { + $new_setting['title'] = $setting['title_method']; + } + } + + $method_settings[ $new_setting['id'] ] = $new_setting; + } + } + } + + return $method_settings; + } + + public function get_setting_sections() { + $sections = array( + '' => _x( 'General', 'shipments', 'woocommerce-germanized' ), + ); + + if ( $this->supports_customer_return_requests() ) { + $sections['returns'] = _x( 'Return Requests', 'shipments', 'woocommerce-germanized' ); + } + + return $sections; + } + + /** + * @param \Vendidero\Germanized\Shipments\Shipment $shipment + * + * @return ShipmentLabel|false + */ + public function get_label( $shipment ) { + return apply_filters( "{$this->get_hook_prefix()}label", false, $shipment, $this ); + } + + /** + * @param \Vendidero\Germanized\Shipments\Shipment $shipment + */ + public function get_label_fields_html( $shipment ) { + return apply_filters( "{$this->get_hook_prefix()}label_fields_html", '', $shipment, $this ); + } + + /** + * @param \Vendidero\Germanized\Shipments\Shipment $shipment + * @param mixed $props + */ + public function create_label( $shipment, $props = false ) { + $result = new \WP_Error( 'shipping-provider', _x( 'This shipping provider does not support creating labels.', 'shipments', 'woocommerce-germanized' ) ); + + return $result; + } +} diff --git a/packages/woocommerce-germanized-shipments/src/SimpleShipment.php b/packages/woocommerce-germanized-shipments/src/SimpleShipment.php new file mode 100644 index 000000000..f57e2fd71 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/SimpleShipment.php @@ -0,0 +1,384 @@ + 0, + ); + + /** + * Returns the shipment type. + * + * @return string + */ + public function get_type() { + return 'simple'; + } + + /** + * Returns the order id belonging to the shipment. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return integer + */ + public function get_order_id( $context = 'view' ) { + return $this->get_prop( 'order_id', $context ); + } + + /** + * Set shipment order id. + * + * @param string $order_id The order id. + */ + public function set_order_id( $order_id ) { + // Reset order object + $this->order = null; + + $this->set_prop( 'order_id', absint( $order_id ) ); + } + + /** + * Set shipment order. + * + * @param Order $order_shipment The order shipment. + */ + public function set_order_shipment( &$order_shipment ) { + $this->order_shipment = $order_shipment; + } + + /** + * Tries to fetch the order for the current shipment. + * + * @return bool|WC_Order|null + */ + public function get_order() { + if ( is_null( $this->order ) ) { + $this->order = ( $this->get_order_id() > 0 ? wc_get_order( $this->get_order_id() ) : false ); + } + + return $this->order; + } + + /** + * Returns the order shipment instance. Loads from DB if not yet exists. + * + * @return bool|Order + */ + public function get_order_shipment() { + if ( is_null( $this->order_shipment ) ) { + $order = $this->get_order(); + $this->order_shipment = ( $order ? wc_gzd_get_shipment_order( $order ) : false ); + } + + return $this->order_shipment; + } + + /** + * Sync the shipment with it's corresponding order. + * + * @param array $args + * + * @return bool + */ + public function sync( $args = array() ) { + try { + + if ( ! $order_shipment = $this->get_order_shipment() ) { + throw new Exception( _x( 'Invalid shipment order', 'shipments', 'woocommerce-germanized' ) ); + } + + /** + * Hotfix WCML infinite loop + * + */ + if ( function_exists( 'wc_gzd_remove_class_filter' ) ) { + wc_gzd_remove_class_filter( 'woocommerce_order_get_items', 'WCML_Orders', 'woocommerce_order_get_items', 10 ); + } + + $order = $order_shipment->get_order(); + + /** + * Make sure that manually adjusted providers are not overridden by syncing. + */ + $default_provider_instance = wc_gzd_get_order_shipping_provider( $order ); + $default_provider = $default_provider_instance ? $default_provider_instance->get_name() : ''; + $provider = $this->get_shipping_provider( 'edit' ); + $address_data = array_merge( + ( $order->has_shipping_address() ? $order->get_address( 'shipping' ) : $order->get_address( 'billing' ) ), + array( + 'email' => $order->get_billing_email(), + 'phone' => $order->get_billing_phone(), + ) + ); + + // Prefer shipping phone in case exists + if ( is_callable( array( $order, 'get_shipping_phone' ) ) && $order->get_shipping_phone() ) { + $address_data['phone'] = $order->get_shipping_phone(); + } + + /** + * Fix to make sure that we are not syncing formatted customer titles (e.g. Herr) + * which prevents shipment addresses from being translated. + */ + if ( isset( $address_data['title'] ) && ! empty( $address_data['title'] ) ) { + if ( $title = $order->get_meta( '_shipping_title', true ) ) { + $address_data['title'] = $title; + } + } + + /** + * Force the country to have a max length of 2. + * https://github.com/woocommerce/woocommerce/issues/27521 + */ + $country = substr( strtoupper( ( $order->has_shipping_address() ? $order->get_shipping_country() : $order->get_billing_country() ) ), 0, 2 ); + $packaging_id = $this->get_packaging_id( 'edit' ); + + $dimensions = array( + 'width' => $this->get_width( 'edit' ), + 'length' => $this->get_length( 'edit' ), + 'height' => $this->get_height( 'edit' ), + ); + + $args = wp_parse_args( + $args, + array( + 'order_id' => $order->get_id(), + 'shipping_method' => wc_gzd_get_shipment_order_shipping_method_id( $order ), + 'shipping_provider' => ( ! empty( $provider ) ) ? $provider : $default_provider, + 'packaging_id' => $this->get_packaging_id( 'edit' ), + 'address' => $address_data, + 'country' => $country, + 'weight' => $this->get_weight( 'edit' ), + 'packaging_weight' => $this->get_packaging_weight( 'edit' ), + 'length' => $dimensions['length'], + 'width' => $dimensions['width'], + 'height' => $dimensions['height'], + 'additional_total' => $order_shipment->calculate_shipment_additional_total( $this ), + ) + ); + + /** + * Filter to allow adjusting the shipment props synced from the corresponding order. + * + * @param mixed $args The properties in key => value pairs. + * @param SimpleShipment $shipment The shipment object. + * @param Order $order_shipment The shipment order object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + $args = apply_filters( 'woocommerce_gzd_shipment_sync_props', $args, $this, $order_shipment ); + + $this->set_props( $args ); + + /** + * Action that fires after a shipment has been synced. Syncing is used to + * keep the shipment in sync with the corresponding order. + * + * @param SimpleShipment $shipment The shipment object. + * @param Order $order_shipment The shipment order object. + * @param array $args Array containing properties in key => value pairs to be updated. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_shipment_synced', $this, $order_shipment, $args ); + + } catch ( Exception $e ) { + return false; + } + + return true; + } + + /** + * Sync items with the corresponding order items. + * Limits quantities and removes non-existing items. + * + * @param array $args + * + * @return bool + */ + public function sync_items( $args = array() ) { + try { + + if ( ! $order_shipment = $this->get_order_shipment() ) { + throw new Exception( _x( 'Invalid shipment order', 'shipments', 'woocommerce-germanized' ) ); + } + + $order = $order_shipment->get_order(); + + $args = wp_parse_args( + $args, + array( + 'items' => array(), + ) + ); + + $available_items = $order_shipment->get_available_items_for_shipment( + array( + 'shipment_id' => $this->get_id(), + 'exclude_current_shipment' => true, + ) + ); + + foreach ( $available_items as $item_id => $item_data ) { + + if ( $order_item = $order->get_item( $item_id ) ) { + $quantity = $item_data['max_quantity']; + + if ( ! empty( $args['items'] ) ) { + if ( isset( $args['items'][ $item_id ] ) ) { + $new_quantity = absint( $args['items'][ $item_id ] ); + + if ( $new_quantity < $quantity ) { + $quantity = $new_quantity; + } + } else { + continue; + } + } + + if ( ! $shipment_item = $this->get_item_by_order_item_id( $item_id ) ) { + $shipment_item = wc_gzd_create_shipment_item( $this, $order_item, array( 'quantity' => $quantity ) ); + + $this->add_item( $shipment_item ); + } else { + $shipment_item->sync( array( 'quantity' => $quantity ) ); + } + } + } + + foreach ( $this->get_items() as $item ) { + + // Remove non-existent items + if ( ! $order_item = $order->get_item( $item->get_order_item_id() ) ) { + $this->remove_item( $item->get_id() ); + } + } + + // Sync packaging + $this->sync_packaging(); + + /** + * Action that fires after items of a shipment have been synced. + * + * @param SimpleShipment $shipment The shipment object. + * @param Order $order_shipment The shipment order object. + * @param array $args Array containing additional data e.g. items. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_shipment_items_synced', $this, $order_shipment, $args ); + + } catch ( Exception $e ) { + return false; + } + + return true; + } + + /** + * Returns available shipment methods by checking the corresponding order. + * + * @return string[] + */ + public function get_available_shipping_methods() { + $methods = array(); + + if ( $order = $this->get_order() ) { + $items = $order->get_shipping_methods(); + + foreach ( $items as $item ) { + $methods[ $item->get_method_id() . ':' . $item->get_instance_id() ] = $item->get_name(); + } + } + + return $methods; + } + + /** + * Returns the number of items available for shipment. + * + * @return int|mixed|void + */ + public function get_shippable_item_count() { + if ( $order_shipment = $this->get_order_shipment() ) { + return $order_shipment->get_shippable_item_count(); + } + + return 0; + } + + /** + * Returns whether the Shipment needs additional items or not. + * + * @param bool|integer[] $available_items + * + * @return bool + */ + public function needs_items( $available_items = false ) { + + if ( ! $available_items && ( $order = wc_gzd_get_shipment_order( $this->get_order() ) ) ) { + $available_items = array_keys( $order->get_available_items_for_shipment() ); + } + + return ( $this->is_editable() && ! $this->contains_order_item( $available_items ) ); + } + + /** + * Returns the edit shipment URL. + * + * @return mixed|string|void + */ + public function get_edit_shipment_url() { + /** + * Filter to adjust the edit Shipment admin URL. + * + * The dynamic portion of this hook, `$this->get_hook_prefix()` is used to construct a + * unique hook for a shipment type. + * + * Example hook name: woocommerce_gzd_shipment_get_edit_url + * + * @param string $url The URL. + * @param Shipment $this The shipment object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( "{$this->get_hook_prefix()}edit_url", get_admin_url( null, 'post.php?post=' . $this->get_order_id() . '&action=edit&shipment_id=' . $this->get_id() ), $this ); + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Validation.php b/packages/woocommerce-germanized-shipments/src/Validation.php new file mode 100644 index 000000000..c69a218aa --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Validation.php @@ -0,0 +1,234 @@ +get_id() ) { + self::new_order( $order ); + } + }, + 300, + 1 + ); + }, + 10, + 1 + ); + + add_action( 'woocommerce_delete_order', array( __CLASS__, 'delete_order' ), 10, 1 ); + + foreach ( array( 'cancelled', 'failed', 'refunded' ) as $cancelled_status ) { + add_action( "woocommerce_order_status_{$cancelled_status}", array( __CLASS__, 'maybe_cancel_shipments' ), 10, 2 ); + } + + add_action( 'before_delete_post', array( __CLASS__, 'before_delete_refund' ), 10, 1 ); + add_action( 'woocommerce_delete_order_refund', array( __CLASS__, 'delete_refund_order' ), 10, 1 ); + add_action( 'woocommerce_order_refund_object_updated_props', array( __CLASS__, 'refresh_refund_order' ), 10, 1 ); + + // Check if order is shipped + add_action( 'woocommerce_gzd_shipment_status_changed', array( __CLASS__, 'maybe_update_order_date_shipped' ), 10, 4 ); + + add_action( 'woocommerce_gzd_shipping_provider_deactivated', array( __CLASS__, 'maybe_disable_default_shipping_provider' ), 10 ); + } + + /** + * In case a certain shipping provider is being deactivated make sure that the default + * shipping provider option is removed in case the option equals the deactivated provider. + * + * @param ShippingProvider $provider + */ + public static function maybe_disable_default_shipping_provider( $provider ) { + $default_provider = wc_gzd_get_default_shipping_provider(); + + if ( $default_provider === $provider->get_name() ) { + update_option( 'woocommerce_gzd_shipments_default_shipping_provider', '' ); + } + } + + /** + * @param $shipment_id + * @param $status_from + * @param $status_to + * @param Shipment $shipment + */ + public static function maybe_update_order_date_shipped( $shipment_id, $status_from, $status_to, $shipment ) { + if ( 'simple' === $shipment->get_type() && ( $order = $shipment->get_order() ) ) { + self::check_order_shipped( $order ); + } + } + + public static function check_order_shipped( $order ) { + if ( $shipment_order = wc_gzd_get_shipment_order( $order ) ) { + if ( $shipment_order->is_shipped() ) { + /** + * Action that fires as soon as an order has been shipped completely. + * That is the case when the order contains all relevant shipments and all the shipments are marked as shipped. + * + * @param string $order_id The order id. + * + * @since 3.1.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_shipments_order_shipped', $shipment_order->get_order()->get_id() ); + + $shipment_order->get_order()->update_meta_data( '_date_shipped', time() ); + $shipment_order->get_order()->save(); + } else { + $shipment_order->get_order()->delete_meta_data( '_date_shipped' ); + $shipment_order->get_order()->save(); + } + } + } + + /** + * Delete editable shipments if an order is cancelled. + * + * @param $order_id + * @param WC_Order $order + */ + public static function maybe_cancel_shipments( $order_id, $order ) { + $shipments = wc_gzd_get_shipments_by_order( $order ); + + foreach ( $shipments as $shipment ) { + if ( $shipment->is_editable() ) { + $shipment->delete(); + } + } + } + + public static function before_delete_refund( $refund_id ) { + if ( $refund = wc_get_order( $refund_id ) ) { + + if ( is_a( $refund, 'WC_Order_Refund' ) ) { + self::$current_refund_parent_order = $refund->get_parent_id(); + } + } + } + + public static function delete_refund_order( $refund_id ) { + if ( false !== self::$current_refund_parent_order ) { + + if ( $order_shipment = wc_gzd_get_shipment_order( self::$current_refund_parent_order ) ) { + $order_shipment->validate_shipments(); + } + + self::$current_refund_parent_order = false; + } + } + + public static function refresh_refund_order( $refund ) { + if ( $refund->get_parent_id() <= 0 ) { + return; + } + + if ( $order_shipment = wc_gzd_get_shipment_order( $refund->get_parent_id() ) ) { + $order_shipment->validate_shipments(); + } + } + + public static function delete_order( $order_id ) { + if ( $order_shipment = wc_gzd_get_shipment_order( $order_id ) ) { + + foreach ( $order_shipment->get_shipments() as $shipment ) { + + if ( $shipment->is_editable() ) { + $order_shipment->remove_shipment( $shipment->get_id() ); + } + } + + $order_shipment->save(); + } + } + + public static function new_order( $order ) { + if ( $order_shipment = wc_gzd_get_shipment_order( $order ) ) { + $order_shipment->validate_shipments(); + } + } + + public static function update_order( $order_id ) { + if ( $order_shipment = wc_gzd_get_shipment_order( $order_id ) ) { + $order_shipment->validate_shipments(); + } + } + + public static function delete_order_item( $order_item_id ) { + try { + if ( $order_id = wc_get_order_id_by_order_item_id( $order_item_id ) ) { + + if ( $order_shipment = wc_gzd_get_shipment_order( $order_id ) ) { + foreach ( $order_shipment->get_shipments() as $shipment ) { + + if ( $shipment->is_editable() ) { + if ( $item = $shipment->get_item_by_order_item_id( $order_item_id ) ) { + $shipment->remove_item( $item->get_id() ); + } + } + } + + $order_shipment->save(); + } + } + } catch ( Exception $e ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch + } + } + + public static function create_order_item( $order_item_id, $order_item, $order_id ) { + if ( $order_shipment = wc_gzd_get_shipment_order( $order_id ) ) { + $order_shipment->validate_shipments(); + } + } + + protected static function is_admin_save_order_request() { + $is_admin_order_save_request = doing_action( 'save_post' ); + + /** + * Detect admin order adjustments e.g. add item, remove item, save post etc. and + * prevent singular order item hooks from executing to prevent multiple shipment validation requests + * which will execute on order save hook as well. + */ + if ( ! $is_admin_order_save_request && wp_doing_ajax() && isset( $_REQUEST['action'] ) && isset( $_REQUEST['order_id'] ) && strpos( wc_clean( wp_unslash( $_REQUEST['action'] ) ), 'woocommerce_' ) !== false ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $is_admin_order_save_request = true; + } + + return $is_admin_order_save_request; + } + + /** + * @param $order_item_id + * @param WC_Order_Item $order_item + */ + public static function update_order_item( $order_item_id, $order_item ) { + if ( ! self::is_admin_save_order_request() ) { + if ( is_callable( array( $order_item, 'get_order_id' ) ) ) { + + if ( $order_shipment = wc_gzd_get_shipment_order( $order_item->get_order_id() ) ) { + $order_shipment->validate_shipments(); + } + } + } + } +} diff --git a/packages/woocommerce-germanized-shipments/src/WPMLHelper.php b/packages/woocommerce-germanized-shipments/src/WPMLHelper.php new file mode 100644 index 000000000..cd7f1054c --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/WPMLHelper.php @@ -0,0 +1,142 @@ +get_shipping_providers() as $provider ) { + add_filter( "woocommerce_gzd_shipping_provider_{$provider->get_name()}_get_tracking_desc_placeholder", array( __CLASS__, 'filter_shipping_provider_placeholder' ), 10, 2 ); + add_filter( "woocommerce_gzd_shipping_provider_{$provider->get_name()}_get_tracking_url_placeholder", array( __CLASS__, 'filter_shipping_provider_url' ), 10, 2 ); + add_filter( "woocommerce_gzd_shipping_provider_{$provider->get_name()}_get_return_instructions", array( __CLASS__, 'filter_shipping_provider_return_instructions' ), 10, 2 ); + } + } + + public static function filter_shipping_provider_return_instructions( $instructions, $provider ) { + $string_name = 'return_instructions'; + $translated_string = apply_filters( 'wpml_translate_string', $instructions, self::get_shipping_provider_string_id( $string_name, $provider ), self::get_shipping_provider_string_package( $string_name, $provider ) ); + + return $translated_string; + } + + public static function filter_shipping_provider_url( $placeholder, $provider ) { + $string_name = 'tracking_url_placeholder'; + $translated_string = apply_filters( 'wpml_translate_string', $placeholder, self::get_shipping_provider_string_id( $string_name, $provider ), self::get_shipping_provider_string_package( $string_name, $provider ) ); + + return $translated_string; + } + + public static function filter_shipping_provider_placeholder( $placeholder, $provider ) { + $string_name = 'tracking_desc_placeholder'; + $translated_string = apply_filters( 'wpml_translate_string', $placeholder, self::get_shipping_provider_string_id( $string_name, $provider ), self::get_shipping_provider_string_package( $string_name, $provider ) ); + + return $translated_string; + } + + /** + * @param integer $provider_id + * @param Simple $provider + */ + public static function register_shipping_provider_strings( $provider_id, $provider ) { + + foreach ( self::get_shipping_provider_strings() as $string_name => $title ) { + $title = sprintf( $title, $provider->get_title() ); + $getter = "get_{$string_name}"; + + if ( is_callable( array( $provider, $getter ) ) ) { + $value = $provider->{$getter}(); + + do_action( 'wpml_register_string', $value, self::get_shipping_provider_string_id( $string_name, $provider ), self::get_shipping_provider_string_package( $string_name, $provider ), $title, 'AREA' ); + } + } + } + + protected static function get_shipping_provider_strings() { + $strings = array( + 'tracking_desc_placeholder' => _x( '%s tracking description', 'shipments', 'woocommerce-germanized' ), + 'tracking_url_placeholder' => _x( '%s tracking URL', 'shipments', 'woocommerce-germanized' ), + 'return_instructions' => _x( '%s return instructions', 'shipments', 'woocommerce-germanized' ), + ); + + return $strings; + } + + /** + * @param $string_name + * @param Simple $provider + */ + protected static function get_shipping_provider_string_id( $string_name, $provider ) { + return "woocommerce_gzd_shipping_provider_{$provider->get_name()}_{$string_name}"; + } + + /** + * @param $string_name + * @param Simple $provider + */ + protected static function get_shipping_provider_string_package( $string_name, $provider ) { + $strings = self::get_shipping_provider_strings(); + $package = array(); + + if ( array_key_exists( $string_name, $strings ) ) { + $title = sprintf( $strings[ $string_name ], $provider->get_title() ); + + $package = array( + 'kind' => 'Shipping Provider', + 'name' => "{$provider->get_name()}_{$string_name}", + 'edit_link' => $provider->get_edit_link(), + 'title' => $title, + ); + } + + return $package; + } + + /** + * @param $emails + */ + public static function register_emails( $emails ) { + $emails['WC_GZD_Email_Customer_Shipment'] = 'customer_shipment'; + $emails['WC_GZD_Email_Customer_Return_Shipment'] = 'customer_return_shipment'; + $emails['WC_GZD_Email_Customer_Return_Shipment_Delivered'] = 'customer_return_shipment_delivered'; + $emails['WC_GZD_Email_Customer_Guest_Return_Shipment_Request'] = 'customer_guest_return_shipment_request'; + + return $emails; + } +} diff --git a/packages/woocommerce-germanized-shipments/templates/emails/admin-new-return-shipment-request.php b/packages/woocommerce-germanized-shipments/templates/emails/admin-new-return-shipment-request.php new file mode 100644 index 000000000..0b3d10afb --- /dev/null +++ b/packages/woocommerce-germanized-shipments/templates/emails/admin-new-return-shipment-request.php @@ -0,0 +1,60 @@ + + + +

get_formatted_sender_full_name() ) ); ?>

+ + + +

get_billing_first_name() ) ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch ?>

+ +

+ get_order_number() ) ); ?> +

+ +

+ +

+ +

+ + + +

get_billing_first_name() ) ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch ?>

+ +

+ +

+ + + +

get_billing_first_name() ) ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch ?>

+ +

+ +

+ + + +

get_billing_first_name() ) ); // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch ?>

+ +

+ +

+ + + + + +
+ $shipment ) : + $count++; + ?> + 1 ) : ?> +

+ + + get_est_delivery_date() ) : ?> +

get_est_delivery_date(), wc_date_format() ) ); ?>

+ + + has_tracking() ) : ?> + get_tracking_url() ) : ?> +

+ + + has_tracking_instruction() ) : ?> +

get_tracking_instruction() ); ?>

+ + +

+ + +
diff --git a/packages/woocommerce-germanized-shipments/templates/emails/email-return-shipment-instructions.php b/packages/woocommerce-germanized-shipments/templates/emails/email-return-shipment-instructions.php new file mode 100644 index 000000000..2789a1d36 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/templates/emails/email-return-shipment-instructions.php @@ -0,0 +1,26 @@ +get_shipping_provider_instance(); +?> + +has_return_instructions() ) : ?> +

get_return_instructions() ) ) . PHP_EOL ); ?>

+ diff --git a/packages/woocommerce-germanized-shipments/templates/emails/email-shipment-address.php b/packages/woocommerce-germanized-shipments/templates/emails/email-shipment-address.php new file mode 100644 index 000000000..f355c2f80 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/templates/emails/email-shipment-address.php @@ -0,0 +1,34 @@ + + + + + + +
+

+ +
+ get_formatted_address() ); ?> +
+
diff --git a/packages/woocommerce-germanized-shipments/templates/emails/email-shipment-details.php b/packages/woocommerce-germanized-shipments/templates/emails/email-shipment-details.php new file mode 100644 index 000000000..a6ed2569d --- /dev/null +++ b/packages/woocommerce-germanized-shipments/templates/emails/email-shipment-details.php @@ -0,0 +1,87 @@ + + +

+ get_edit_shipment_url() ) . '">'; + $after = ''; + } else { + $before = ''; + $after = ''; + } + /* translators: %s: Order ID. */ + echo wp_kses_post( $before . ( ! $sent_to_admin ? sprintf( _x( 'Details to your %s', 'shipments', 'woocommerce-germanized' ), wc_gzd_get_shipment_label_title( $shipment->get_type() ) ) : sprintf( _x( '[%1$s #%2$s]', 'shipments', 'woocommerce-germanized' ), wc_gzd_get_shipment_label_title( $shipment->get_type() ), $shipment->get_shipment_number() ) ) . $after ); + ?> +

+ +
+ + + + + + + + + $sent_to_admin, + 'show_image' => false, + 'image_size' => array( 32, 32 ), + 'plain_text' => $plain_text, + 'sent_to_admin' => $sent_to_admin, + ) + ); + ?> + +
+
+ + diff --git a/packages/woocommerce-germanized-shipments/templates/emails/email-shipment-items.php b/packages/woocommerce-germanized-shipments/templates/emails/email-shipment-items.php new file mode 100644 index 000000000..e17d2f062 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/templates/emails/email-shipment-items.php @@ -0,0 +1,114 @@ + $item ) : + $product = $item->get_product(); + $sku = $item->get_sku(); + $purchase_note = ''; + $image = ''; + + /** + * Filter to decide whether a specific ShipmentItem is visible within email table or not. + * + * @param boolean $is_visible Whether the ShipmentItem is visible or not. + * @param ShipmentItem $item The ShipmentItem object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + if ( ! apply_filters( 'woocommerce_gzd_shipment_item_visible', true, $item ) ) { + continue; + } + + if ( is_object( $product ) ) { + $image = $product->get_image( $image_size ); + } + + ?> + + + get_name(), $item, false ) ); + + // SKU. + if ( $show_sku && $sku ) { + echo wp_kses_post( ' (#' . $sku . ')' ); + } + + /* + * Action that fires while outputting meta data for a ShipmentItem table display in an Email. + * + * @param integer $item_id The shipment item id. + * @param \Vendidero\Germanized\Shipments\ShipmentItem $item The shipment item instance. + * @param \Vendidero\Germanized\Shipments\Shipment $shipment The shipment instance. + * @param boolean $plain_text Whether this email is in plaintext format or not. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_shipment_item_meta', $item_id, $item, $shipment, $plain_text ); + + ?> + + + get_quantity(), $item ) ); + ?> + + + + diff --git a/packages/woocommerce-germanized-shipments/templates/emails/email-shipment-tracking.php b/packages/woocommerce-germanized-shipments/templates/emails/email-shipment-tracking.php new file mode 100644 index 000000000..4d5cf3d4a --- /dev/null +++ b/packages/woocommerce-germanized-shipments/templates/emails/email-shipment-tracking.php @@ -0,0 +1,42 @@ + + + + + + +
+

+ + get_est_delivery_date() ) : ?> +

get_est_delivery_date(), wc_date_format() ) ); ?>

+ + + get_tracking_url() ) : ?> +

+ + + has_tracking_instruction() ) : ?> +

get_tracking_instruction() ); ?>

+ +
diff --git a/packages/woocommerce-germanized-shipments/templates/emails/plain/admin-new-return-shipment-request.php b/packages/woocommerce-germanized-shipments/templates/emails/plain/admin-new-return-shipment-request.php new file mode 100644 index 000000000..14481e946 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/templates/emails/plain/admin-new-return-shipment-request.php @@ -0,0 +1,41 @@ +get_formatted_sender_full_name() ) ) . "\n\n"; + +echo "\n\n"; + +/* This hook is documented in templates/emails/customer-shipment.php */ +do_action( 'woocommerce_gzd_email_shipment_details', $shipment, $sent_to_admin, $plain_text, $email ); + +/** + * Show user-defined additional content - this is set in each email's settings. + */ +if ( $additional_content ) { + echo esc_html( wp_strip_all_tags( wptexturize( $additional_content ) ) ); + echo "\n\n----------------------------------------\n\n"; +} + +echo "\n----------------------------------------\n\n"; + +echo wp_kses_post( apply_filters( 'woocommerce_email_footer_text', get_option( 'woocommerce_email_footer_text' ) ) ); diff --git a/packages/woocommerce-germanized-shipments/templates/emails/plain/customer-guest-return-shipment-request.php b/packages/woocommerce-germanized-shipments/templates/emails/plain/customer-guest-return-shipment-request.php new file mode 100644 index 000000000..132b76d58 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/templates/emails/plain/customer-guest-return-shipment-request.php @@ -0,0 +1,40 @@ +get_billing_first_name() ) ) . "\n\n"; // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch + +echo sprintf( esc_html_x( 'You\'ve requested a return to your order %s. Please follow the link to add your return request.', 'shipments', 'woocommerce-germanized' ), esc_html( $order->get_order_number() ) ) . "\n\n"; + +echo esc_url( $add_return_request_url ) . "\n\n"; + +/** + * Show user-defined additional content - this is set in each email's settings. + */ +if ( $additional_content ) { + echo esc_html( wp_strip_all_tags( wptexturize( $additional_content ) ) ); + echo "\n\n----------------------------------------\n\n"; +} + +echo "\n----------------------------------------\n\n"; + +echo wp_kses_post( apply_filters( 'woocommerce_email_footer_text', get_option( 'woocommerce_email_footer_text' ) ) ); diff --git a/packages/woocommerce-germanized-shipments/templates/emails/plain/customer-return-shipment-delivered.php b/packages/woocommerce-germanized-shipments/templates/emails/plain/customer-return-shipment-delivered.php new file mode 100644 index 000000000..4c5660934 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/templates/emails/plain/customer-return-shipment-delivered.php @@ -0,0 +1,43 @@ +get_billing_first_name() ) ) . "\n\n"; // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch + +echo esc_html_x( 'Thank you! Your return has been received successfully. There are more details below for your reference:', 'shipments', 'woocommerce-germanized' ); + +echo "\n\n"; + +/* This hook is documented in templates/emails/customer-shipment.php */ +do_action( 'woocommerce_gzd_email_shipment_details', $shipment, $sent_to_admin, $plain_text, $email ); + +/** + * Show user-defined additional content - this is set in each email's settings. + */ +if ( $additional_content ) { + echo esc_html( wp_strip_all_tags( wptexturize( $additional_content ) ) ); + echo "\n\n----------------------------------------\n\n"; +} + +echo "\n----------------------------------------\n\n"; + +echo wp_kses_post( apply_filters( 'woocommerce_email_footer_text', get_option( 'woocommerce_email_footer_text' ) ) ); diff --git a/packages/woocommerce-germanized-shipments/templates/emails/plain/customer-return-shipment.php b/packages/woocommerce-germanized-shipments/templates/emails/plain/customer-return-shipment.php new file mode 100644 index 000000000..6f2fcdcd7 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/templates/emails/plain/customer-return-shipment.php @@ -0,0 +1,48 @@ +get_billing_first_name() ) ) . "\n\n"; // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch + + +if ( $is_confirmation ) { + echo esc_html_x( 'Your return request has been accepted. Please follow the instructions beneath to return your shipment.', 'shipments', 'woocommerce-germanized' ); +} else { + echo esc_html_x( 'A new return has been added to your order. Please follow the instructions beneath to return your shipment.', 'shipments', 'woocommerce-germanized' ); +} + +echo "\n\n"; + +/* This hook is documented in templates/emails/customer-shipment.php */ +do_action( 'woocommerce_gzd_email_shipment_details', $shipment, $sent_to_admin, $plain_text, $email ); + +/** + * Show user-defined additional content - this is set in each email's settings. + */ +if ( $additional_content ) { + echo esc_html( wp_strip_all_tags( wptexturize( $additional_content ) ) ); + echo "\n\n----------------------------------------\n\n"; +} + +echo "\n----------------------------------------\n\n"; + +echo wp_kses_post( apply_filters( 'woocommerce_email_footer_text', get_option( 'woocommerce_email_footer_text' ) ) ); diff --git a/packages/woocommerce-germanized-shipments/templates/emails/plain/customer-shipment.php b/packages/woocommerce-germanized-shipments/templates/emails/plain/customer-shipment.php new file mode 100644 index 000000000..751b764c4 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/templates/emails/plain/customer-shipment.php @@ -0,0 +1,49 @@ +get_billing_first_name() ) ) . "\n\n"; // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch + +if ( $partial_shipment ) { + /* translators: %s: Site title */ + printf( esc_html_x( 'Your order on %1$s has been partially shipped via %2$s. Find details below for your reference:', 'shipments', 'woocommerce-germanized' ), wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ), wc_gzd_get_shipment_shipping_provider_title( $shipment ) ); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped +} else { + /* translators: %s: Site title */ + printf( esc_html_x( 'Your order on %1$s has been shipped via %2$s. Find details below for your reference:', 'shipments', 'woocommerce-germanized' ), wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ), wc_gzd_get_shipment_shipping_provider_title( $shipment ) ); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped +} + +echo "\n\n"; + +/* This hook is documented in templates/emails/customer-shipment.php */ +do_action( 'woocommerce_gzd_email_shipment_details', $shipment, $sent_to_admin, $plain_text, $email ); + +/** + * Show user-defined additional content - this is set in each email's settings. + */ +if ( $additional_content ) { + echo esc_html( wp_strip_all_tags( wptexturize( $additional_content ) ) ); + echo "\n\n----------------------------------------\n\n"; +} + +echo "\n----------------------------------------\n\n"; + +echo wp_kses_post( apply_filters( 'woocommerce_email_footer_text', get_option( 'woocommerce_email_footer_text' ) ) ); diff --git a/packages/woocommerce-germanized-shipments/templates/emails/plain/email-order-shipments.php b/packages/woocommerce-germanized-shipments/templates/emails/plain/email-order-shipments.php new file mode 100644 index 000000000..2c8b85934 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/templates/emails/plain/email-order-shipments.php @@ -0,0 +1,47 @@ + $shipment ) { + $count++; + + echo "\n"; + + if ( count( $shipments ) > 1 ) { + echo sprintf( esc_html_x( 'Shipment %1$d of %2$d', 'shipments', 'woocommerce-germanized' ), esc_html( $count ), esc_html( count( $shipments ) ) ) . "\n\n"; + } + + if ( $shipment->get_est_delivery_date() ) { + echo esc_html( _x( 'Estimated date:', 'shipments', 'woocommerce-germanized' ) ) . ' ' . esc_html( wc_format_datetime( $shipment->get_est_delivery_date(), wc_date_format() ) ) . "\n\n"; + } + + if ( $shipment->has_tracking() ) { + if ( $shipment->get_tracking_url() ) { + echo esc_html( _x( 'Track your shipment', 'shipments', 'woocommerce-germanized' ) ) . ': ' . esc_url( $shipment->get_tracking_url() ) . "\n"; + } + + if ( $shipment->has_tracking_instruction() ) { + echo esc_html( $shipment->get_tracking_instruction( true ) ) . "\n"; + } + } else { + echo esc_html( _x( 'Sorry, this shipment does currently not support tracking.', 'shipments', 'woocommerce-germanized' ) ) . "\n"; + } +} diff --git a/packages/woocommerce-germanized-shipments/templates/emails/plain/email-return-shipment-instructions.php b/packages/woocommerce-germanized-shipments/templates/emails/plain/email-return-shipment-instructions.php new file mode 100644 index 000000000..ee24b7d3b --- /dev/null +++ b/packages/woocommerce-germanized-shipments/templates/emails/plain/email-return-shipment-instructions.php @@ -0,0 +1,23 @@ +get_shipping_provider_instance(); + +if ( $provider && $provider->has_return_instructions() ) { + echo wp_kses_post( wpautop( wptexturize( $provider->get_return_instructions() ) ) . PHP_EOL ); +} diff --git a/packages/woocommerce-germanized-shipments/templates/emails/plain/email-shipment-address.php b/packages/woocommerce-germanized-shipments/templates/emails/plain/email-shipment-address.php new file mode 100644 index 000000000..2eaac15ae --- /dev/null +++ b/packages/woocommerce-germanized-shipments/templates/emails/plain/email-shipment-address.php @@ -0,0 +1,20 @@ +#i', "\n", $shipment->get_formatted_address() ) . "\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped diff --git a/packages/woocommerce-germanized-shipments/templates/emails/plain/email-shipment-details.php b/packages/woocommerce-germanized-shipments/templates/emails/plain/email-shipment-details.php new file mode 100644 index 000000000..51c4b8206 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/templates/emails/plain/email-shipment-details.php @@ -0,0 +1,43 @@ +get_type() ) ) : sprintf( _x( '[%1$s #%2$s]', 'shipments', 'woocommerce-germanized' ), wc_gzd_get_shipment_label_title( $shipment->get_type() ), $shipment->get_shipment_number() ) ) ) ) . "\n"; +echo "\n" . wc_gzd_get_email_shipment_items( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + $shipment, + array( + 'show_sku' => $sent_to_admin, + 'show_image' => false, + 'image_size' => array( 32, 32 ), + 'plain_text' => true, + 'sent_to_admin' => $sent_to_admin, + ) +); + +echo "==========\n\n"; + +if ( $sent_to_admin ) { + /* translators: %s: Shipment link. */ + echo "\n" . sprintf( esc_html_x( 'View shipment: %s', 'shipments', 'woocommerce-germanized' ), esc_url( $shipment->get_edit_shipment_url() ) ) . "\n"; +} + +/* This hook is documented in templates/emails/customer-shipment.php */ +do_action( 'woocommerce_gzd_email_after_shipment_table', $shipment, $sent_to_admin, $plain_text, $email ); diff --git a/packages/woocommerce-germanized-shipments/templates/emails/plain/email-shipment-items.php b/packages/woocommerce-germanized-shipments/templates/emails/plain/email-shipment-items.php new file mode 100644 index 000000000..2fa1d8308 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/templates/emails/plain/email-shipment-items.php @@ -0,0 +1,46 @@ + $item ) : + $product = $item->get_product(); + $sku = $item->get_sku(); + $purchase_note = ''; + + /* This filter is documented in templates/emails/email-shipment-items.php */ + if ( ! apply_filters( 'woocommerce_gzd_shipment_item_visible', true, $item ) ) { + continue; + } + + /* This filter is documented in templates/emails/email-shipment-items.php */ + echo wp_kses_post( apply_filters( 'woocommerce_gzd_shipment_item_name', $item->get_name(), $item, false ) ); + + if ( $show_sku && $sku ) { + echo ' (#' . esc_html( $sku ) . ')'; + } + + /* This filter is documented in templates/emails/email-shipment-items.php */ + echo ' X ' . wp_kses_post( apply_filters( 'woocommerce_gzd_email_shipment_item_quantity', $item->get_quantity(), $item ) ); + echo "\n"; + + /* This hook is documented in templates/emails/email-shipment-items.php */ + do_action( 'woocommerce_gzd_shipment_item_meta', $item_id, $item, $shipment, $plain_text ); + + echo "\n\n"; +endforeach; diff --git a/packages/woocommerce-germanized-shipments/templates/emails/plain/email-shipment-tracking.php b/packages/woocommerce-germanized-shipments/templates/emails/plain/email-shipment-tracking.php new file mode 100644 index 000000000..403a94c5a --- /dev/null +++ b/packages/woocommerce-germanized-shipments/templates/emails/plain/email-shipment-tracking.php @@ -0,0 +1,33 @@ +get_est_delivery_date() ) { + echo esc_html( _x( 'Estimated date:', 'shipments', 'woocommerce-germanized' ) ) . ' ' . esc_html( wc_format_datetime( $shipment->get_est_delivery_date(), wc_date_format() ) ) . "\n\n"; +} + +if ( $shipment->get_tracking_url() ) { + echo esc_html( _x( 'Track your shipment', 'shipments', 'woocommerce-germanized' ) ) . ': ' . esc_url( $shipment->get_tracking_url() ) . "\n"; +} + +if ( $shipment->has_tracking_instruction() ) { + echo esc_html( $shipment->get_tracking_instruction( true ) ) . "\n"; +} diff --git a/packages/woocommerce-germanized-shipments/templates/global/empty.php b/packages/woocommerce-germanized-shipments/templates/global/empty.php new file mode 100644 index 000000000..fd3489d94 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/templates/global/empty.php @@ -0,0 +1,21 @@ + +
> + + + + + +

+ + +

+ +

+ + +

+ +
+ + + +

+ + +

+ +
+ + + +
diff --git a/packages/woocommerce-germanized-shipments/templates/myaccount/add-return-shipment.php b/packages/woocommerce-germanized-shipments/templates/myaccount/add-return-shipment.php new file mode 100644 index 000000000..dae87ff75 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/templates/myaccount/add-return-shipment.php @@ -0,0 +1,96 @@ + +

+ +

+ + +

+ +

+ + +
+ + + + + + + + + + + + get_available_items_for_return() as $order_item_id => $item_data ) { + + wc_get_template( + 'shipment/add-return-shipment-item.php', + array( + 'item' => $shipment_order->get_simple_shipment_item( $order_item_id ), + 'order_item_id' => $order_item_id, + 'order' => $order, + 'max_quantity' => $item_data['max_quantity'], + ) + ); + } + + /** + * This action is executed after printing the add return shipment table on the customer account page. + * + * @param WC_Order $order The order instance. + * + * @since 3.1.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_add_return_shipment_details_after_shipment_table_items', $order ); + ?> + +
+ +

+ + + + + + +

+
+ diff --git a/packages/woocommerce-germanized-shipments/templates/myaccount/order-shipments.php b/packages/woocommerce-germanized-shipments/templates/myaccount/order-shipments.php new file mode 100644 index 000000000..07767e924 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/templates/myaccount/order-shipments.php @@ -0,0 +1,53 @@ + + + +

+ + 'simple', + 'shipments' => $shipments, + 'order' => $order, + ) + ); + ?> + + + +

+ +

+ + + +

+ + 'return', + 'shipments' => $returns, + 'order' => $order, + ) + ); + ?> + diff --git a/packages/woocommerce-germanized-shipments/templates/myaccount/shipments.php b/packages/woocommerce-germanized-shipments/templates/myaccount/shipments.php new file mode 100644 index 000000000..4b3531a1c --- /dev/null +++ b/packages/woocommerce-germanized-shipments/templates/myaccount/shipments.php @@ -0,0 +1,113 @@ + + + + + + $column_name ) : ?> + + + + + + + get_item_count(); + ?> + + get_type() ) as $column_id => $column_name ) : ?> + + + + + + + + diff --git a/packages/woocommerce-germanized-shipments/templates/myaccount/view-shipment.php b/packages/woocommerce-germanized-shipments/templates/myaccount/view-shipment.php new file mode 100644 index 000000000..7c28e5636 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/templates/myaccount/view-shipment.php @@ -0,0 +1,42 @@ + +

+ ' . $shipment->get_shipment_number() . '', // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + '' . wc_format_datetime( $shipment->get_date_created() ) . '', // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + '' . wc_gzd_get_shipment_status_name( $shipment->get_status() ) . '' // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + ); + ?> +

+ + diff --git a/packages/woocommerce-germanized-shipments/templates/shipment/add-return-shipment-item.php b/packages/woocommerce-germanized-shipments/templates/shipment/add-return-shipment-item.php new file mode 100644 index 000000000..d4339fa15 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/templates/shipment/add-return-shipment-item.php @@ -0,0 +1,90 @@ + + + + + + + + + get_product(); + $is_visible = $product && $product->is_visible(); + $item_sku = $item->get_sku(); + + /** This filter is documented in templates/myaccount/shipment/shipment-details-item.php */ + $product_permalink = apply_filters( 'woocommerce_gzd_shipment_item_permalink', $is_visible ? $product->get_permalink() : '', $item, $order ); + + /** This filter is documented in templates/emails/email-shipment-items.php */ + echo apply_filters( 'woocommerce_gzd_shipment_item_name', ( $product_permalink ? sprintf( '%s', esc_url( $product_permalink ), $item->get_name() ) : $item->get_name() ) . ( ! empty( $item_sku ) ? ' (' . esc_html( $item_sku ) . ')' : '' ), $item, $is_visible ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + ?> + + + + + + + + + 1 + + 'item[' . esc_attr( $order_item_id ) . '][quantity]', + 'input_value' => 1, + 'max_value' => $max_quantity, + 'min_value' => 1, + ), + $item->get_product() + ); + ?> + + diff --git a/packages/woocommerce-germanized-shipments/templates/shipment/shipment-details-address.php b/packages/woocommerce-germanized-shipments/templates/shipment/shipment-details-address.php new file mode 100644 index 000000000..6e0b8713c --- /dev/null +++ b/packages/woocommerce-germanized-shipments/templates/shipment/shipment-details-address.php @@ -0,0 +1,52 @@ + +
+ +
+ +

+ +
+ get_formatted_address( esc_html_x( 'N/A', 'shipments', 'woocommerce-germanized' ) ) ); ?> + + get_phone() ) : ?> +

get_phone() ); ?>

+ + + get_email() ) : ?> + + +
+ +
+ +
+ + diff --git a/packages/woocommerce-germanized-shipments/templates/shipment/shipment-details-item.php b/packages/woocommerce-germanized-shipments/templates/shipment/shipment-details-item.php new file mode 100644 index 000000000..cee0cfd43 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/templates/shipment/shipment-details-item.php @@ -0,0 +1,93 @@ + + + + + is_visible(); + $item_sku = $item->get_sku(); + + /** + * This filter may adjust the shipment item permalink on the customer account page. + * + * @param string $permalink The permalink. + * @param ShipmentItem $item The shipment item instance. + * @param Shipment $shipment The shipment instance. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + $product_permalink = apply_filters( 'woocommerce_gzd_shipment_item_permalink', $is_visible ? $product->get_permalink() : '', $item, $shipment ); + + /** This filter is documented in templates/emails/email-shipment-items.php */ + echo apply_filters( 'woocommerce_gzd_shipment_item_name', ( $product_permalink ? sprintf( '%s', esc_url( $product_permalink ), $item->get_name() ) : $item->get_name() ) . ( ! empty( $item_sku ) ? ' (' . esc_html( $item_sku ) . ')' : '' ), $item, $is_visible ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + ?> + + + + get_quantity(); + $qty_display = esc_html( $qty ); + + /** + * This filter may adjust the shipment item quantity HTML on the customer account page. + * + * @param string $html The HTML output. + * @param ShipmentItem $item The shipment item instance. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + echo apply_filters( 'woocommerce_gzd_shipment_item_quantity_html', ' ' . sprintf( '× %s', $qty_display ) . '', $item ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + ?> + + + diff --git a/packages/woocommerce-germanized-shipments/templates/shipment/shipment-details-tracking.php b/packages/woocommerce-germanized-shipments/templates/shipment/shipment-details-tracking.php new file mode 100644 index 000000000..a18006785 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/templates/shipment/shipment-details-tracking.php @@ -0,0 +1,44 @@ + +
+ +

+ + get_tracking_url() ) : ?> +

+ + + has_tracking_instruction() ) : ?> +

get_tracking_instruction() ); ?>

+ + +
+ + diff --git a/packages/woocommerce-germanized-shipments/templates/shipment/shipment-details.php b/packages/woocommerce-germanized-shipments/templates/shipment/shipment-details.php new file mode 100644 index 000000000..0050f657e --- /dev/null +++ b/packages/woocommerce-germanized-shipments/templates/shipment/shipment-details.php @@ -0,0 +1,123 @@ +get_order(); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited +$show_receiver_details = is_user_logged_in() && $order && $order->get_user_id() === get_current_user_id(); +$show_tracking = $show_receiver_details && $shipment->has_tracking(); +$shipment_items = $shipment->get_items(); + +if ( 'return' === $shipment->get_type() ) { + if ( $provider = $shipment->get_shipping_provider_instance() ) { + if ( $provider->hide_return_address() ) { + $show_receiver_details = false; + } + } +} +?> +
+ + +

+ + + + + + + + + + + + $item ) { + $product = $item->get_product(); + + wc_get_template( + 'shipment/shipment-details-item.php', + array( + 'shipment' => $shipment, + 'item_id' => $item_id, + 'item' => $item, + 'product' => $product, + ) + ); + } + + /** + * This action is executed after printing the shipment table items on the customer account page. + * + * @param Shipment $shipment The shipment instance. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + do_action( 'woocommerce_gzd_shipment_details_after_shipment_table_items', $shipment ); + ?> + +
+ + +
+ + $shipment ) ); +} + +if ( $show_tracking ) { + wc_get_template( 'shipment/shipment-details-tracking.php', array( 'shipment' => $shipment ) ); +} diff --git a/packages/woocommerce-germanized-shipments/templates/shipment/shipment-return-instructions.php b/packages/woocommerce-germanized-shipments/templates/shipment/shipment-return-instructions.php new file mode 100644 index 000000000..c302b5a50 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/templates/shipment/shipment-return-instructions.php @@ -0,0 +1,41 @@ +get_shipping_provider_instance(); +?> + +has_return_instructions() ) : ?> +
get_return_instructions() ) ) ) ); ?>
+ + +has_status( 'delivered' ) && ( $label = $shipment->get_label() ) ) : ?> +

+ + + diff --git a/packages/woocommerce-germanized-shipments/woocommerce-germanized-shipments.php b/packages/woocommerce-germanized-shipments/woocommerce-germanized-shipments.php new file mode 100644 index 000000000..d7ac18175 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/woocommerce-germanized-shipments.php @@ -0,0 +1,72 @@ + +
+

+ composer install', + '' . esc_html( str_replace( ABSPATH, '', __DIR__ ) ) . '' + ); + ?> +

+
+ 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%0Dk_D-`PR0!IV=>eLlGF3 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 HcmDq$Wz_c2 literal 0 HcmV?d00001 diff --git a/packages/woocommerce-trusted-shops/assets/images/ts/ts_en.png b/packages/woocommerce-trusted-shops/assets/images/ts/ts_en.png new file mode 100755 index 0000000000000000000000000000000000000000..a3c585d0257feeeb435e4add85f411a6c4ff27b6 GIT binary patch literal 68806 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

S@Ldf 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

FDufZ|>`M1F>kGk7Kw#9Jon}cnQBN{Wr`#hlv-D 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 z z^2`f*(TJz|-i^B?^613}x5wSx?CLwAu@`mhxqB{bAvw7+$uJ6JBVG$wV58vZa7zdL zT&$!$$MfR5Oj2$vHFKD0s(LtFiy~2da3a@m6#j0Oxc^qg2fE_{d}$9*s(21yMhuXVk&ys;u#eEN;t zZo5SQlCghN;PdAez&eiCx`h5)KzINkLWm;fzXVt&cpmrekI+I7*LfKkME`po`LsRT z=XUSMKmZU_L!8wqEpr#x?UL`0OtnK8oC|t-~IPdi%|f|4rU^MJ5_!D>;8SMax zLlV9E=z(5^M%&xHnJJ;im*{f7@FM3MAtX<-1NNmKU0hOQj5#>nZ2-HHObR&g=YfXN2OlN42L&Zd*SJ{a)T`zg4j(X*?<~n!l@Vz@&MSlQjLnyAiYj+UP{U>FfiDu9l&(J% z#(S6VfX9satlJN^K&6DVXK_*Me^=*arC*>Jb4ru_x8%F`fMo&z(&J1O6%|2YSf=0w zmmPt%dx>rnvoB&qU7hQ}daoDxUSDf9Q3O1#5u)6S_IcZCCLihQ037L! zkl*qKCbM;j@cY!d9u%`TVyG7i?btP#M^^>8==vQ3MKg<|DAK=Pr*Me*Ntz`U}8 z1g_$VNA?(Dge`6m-c#L+z=7+vl*|E?4+EmJtLtWT2B)p$;JrbM3w-B%sd^b;RlJ|i z0@oD|3>q33Am(*31E&TyzmVY^8BkUn11hzR9Dpk{FfdS>1aL-C|5zM2Y8n8}ypGlL zH|nFnFwT_RP>e4%?D8=(T0h^Ndj9H-2bc&94U3?)QWH)H{=y|SIqK1x+?hglKpPYxAiYn;7-eHB0S?Non=zDKIw?hDM z4}xH0@O`fWgWJEenu(nG%Sj_HjGh7ELqV3rK~0(db9XiJ<)xIARP$>4cxay^=94P5 z+KAEHSZw!X=Pfqq;KNT%P9BWOTR4!4dI6s+o=JPX{|U_iiu}fOyh)U8(gDi^IVXYY#6kpm8%0@yh~(gImoLG@CTRbsY99!THa! z3_J^c4(4>Fu!z8QL(>L_h9Y7W&)I;5A{!1x5$zrvcmduVU>*W8D#Wy!99EXOlHub0`MeI59Di15kg0`@2|M6PJ*n zT3`p)r^nNLBhMlK4~i6vWeP@<7aq)20*WwHEBGrR&oi?hli31Zjdn}5U_Tmd7mn9_ zACKlMh#nJx%*$u;OmqBkU;D5y=zN zWd6NrJgGvy4?tFKP&$Fl{yYYs#o#566DbGB+u>NU9DQLXKu7}xhn9E=thTsj&n^)2S3*93FxN6ouF-my zdX&er4X9lWSHE}?ez(Y%V3fTbFhpBC%*@9_B))-%^Hqk5mzuXgi=FTDj@H8b^=t;Z z!*LlHIr={KDags;WWr$4@bR?*3+I?>6KJ;K+6${$WiFuffP7<$g`odAYFazHO)A_2 z+XbALFH1|>6&h>6HH^OdgY?!G{07WEiib^6R)Ft@gwp_0TtA7dHrOeDsV04j#kWf+Uzjlg7 z{sU5rghv6^S-^t?_PPC3TDo8coDY!yGXGTce_d#hUmHJvHUk$yi780Y5?EPWsj7dt zz}O#yfIJjjDlh^QZ=SS9ZWDBmnwl~ld;$p5?v<65xw*NiDM#>A3^upJ#qMrlpG+Xv zv7VEGeId^m$~32zmX-zv;CpY%x`d-wS63Yz9ME2Hke){(Qb{ z@_;sq&L{xXh(Ex7(BgyxRn)Zl{s5@tgXz3yP0HsN2Mc6UwUF_xk%X?B9U`8e-7Q&|7_@;0*aHU5$~SL+#+t|I7R&03V%xoz2^jcmekbLgM})g54Ri?6tF%n z?(SC?7xvS+5(|K8_3ck#yvZi`P$arVgUBymluFb_7Z?(2R?HWxjh~^vL_|Wu3@rj{ zR~md(378J5uI+;Ul42mLOkM+-p`f7n;O(88n|ph8q6h;lUsh~v_W}u+Ef2T!>vW?J zC_PNSVR@FM|PGC!MnD+Hulo`ghY zH5JhA0zOwY`ngy#G2v)RDylfA4g-?00Nr1J*&xlq53aenIktzHJgyiR6f>tvoeJtK z5x_7EYyTVE#`X1ebYeayhK2u<5B(az)lQ6!t@eF<=yi<*q zom)>U@PFgcf>9-fdw>D)=O_VoFbo3^&ke|rfY;>{F&GdZ<{5_G{}$=sxf#XX`gYId zY)g7<8eF`-qk{1oi-{K<22aZUEGg2ERrbjwaai|~Eb8JIG5k9mOArHmA- z{tUw*lg0OLx!(F5@WKHf1VR}P9G$Iq$W|{D6{moc%xSlH3Y5&%$=V|blp=oTIt^m{ zy&~KuCMF;p$w*E8d3gB7X}$a7N2pOAA;hh*X6Majt0yNAgcm?d%60m80&X-z;H!}0 zMd;RBu>v0&m~9__9@!`S1z>wr*CDp*dKJ0^mfnUOY0KKuy79s)t!E=|=aaRXe zxqF$qT7rpL0L&~&;ae7DD9OTuQ7;&Jvb3wz9simg>GAHOzhO&G{_I zMTAKOz4<``94*~VNxdB%oZR@mg~qv>!^h0V&B4jX$4JV~%ErsW%FDvW!NkVR&&kTq&QAKz4>_neR|_kCHA(4z z`T{)(k=wYtJM*)!czJm-dvP!WT&-Ey`1tr(SlLmW- z^72c#TAI28Tr~gyhksXI#RlLGaI*n8lS)YZS!q5}S|w9+TcHaLv-(!`ubhY)g zw2*cMIFkM~yZpBQ7cE%L`M5YOSUH(^x!5h3IJwO^nD|UBc$wHOd3ktwLBD*QeB}S| zTl~+g{k=OuZ$Kk){#PM>9v;>|3h^*;v9q%>nelL1GV$@4u`*e4aaysl@>yAN^74|i zfK+7pvtj;c1O597v@8Go`yX=vJ^aU@ES*4Bd^$FmPBwIY}`M@0HUW7!yp* zw_)q%^qYhakg#DJA3{i}zPW1@(dYMq!++iwrSpaLjk?!Hg~Yl5gEJ#L{1WvE$u<`g zBLQ6;OI(~ZSk!m9TY%$zbHaf-d419<`IMUAApr5@{4~qQWAnNDKJY>)sSRC`R5)A% zqlhpWTnrV`*5m6%HX10QCk z9xeejWC(~L-{Q&*H-rr}1`p%k<{l@uhCZlWgg?!H`1PBXW*VXX=H-O5nQ9!2f(!nq zjSzZKgaSkcE1y>KP5$GQT2hUG7VhSa*f6BD2J8D z9thHmPBpO+|2Blygs+>Yk?r|o*4t+%%EmhVfMqqul;G0?jf!N?X03qFulj)a9r`}G zLJJ9)3SwVYQf}!uxNuG;*?sx%%0jHT8I^oB+8fdl3KV^7n)kYVDI14owP@9P=mZpl z6P23M4dzUg^cr3h#;y!5Svz#gidK~sdl|Wp+l~czpY5g2-^t-C0|$ae#_DQxv=0rE z4Bf3O(j0fE!k9af&33N25pU%0*`U*nnQ|EdtX)23`9&%(TJN?RJ#O0DEQ6g@9Xo`5lcaQUPSjENzFGO_3(W)k23s=)xAl=g2<`>yckb$1k;1ZC^X`Fm+=)UElg3zNBLrL!6> zbK$Y}7+vVDMJw(V&gqrIekBAOw~4wSZ{>$PX+iBko};b-{voLsF63-H_I;FGK*tX7k1OK+A7!GBnu~(kk^olWGGSg#^|IZ?BKE?i<7(r5gR_4U3?c z`tuxH-`biL35mQPPzp&uh}Jszu%IVH*}98<<~3H-!{7`M$7<+tB1-Ltw#At&bS@?c zNg9MYU~VIbpVh(%|l+n zBq{U#%5bTch3O(kMT=lyMoVF=p{=nE)?AUQY_NDd9;QF}wqrIT%`?~~Q9w`q#raW` zsaJFIbC1hI*iIm7KlFAyzSyW5U|%UQN=Y>EZIatb5(`F`?lW+$8mm>rvfKyzUmyUVl2}`f6WkOWSm!oh)y`ia)4O<_vt7p? zWHRX(R(;tZ*b{Sk!UIgiMQ*qJxQMy0VFDKgM98`;>y=S7-;F%7hxmh*vwb(*A5bW8 zys}iXBzpN9HGdx0p?0nbX3>!x|9^IKFT# zgB?M{XL8E_>W+1n4Dsw0vWs*H6dp6kD9VwWK3L-&#Ak^JV6gC+AdDEqANC zmxnaOmQBYqBw|MRlz@4_oDr>X)Q4{MOiYkxUst{Rx~=J?wpxm(9f?>Wu`Ka|od=*g za42kd%6MtB)Er{HwGQR9Q+sF)tQ0#nxiYYI!2@0 z*L?-cVcVgKkJ|wc5)<-1Um{EJfYq-Kp-E`eV+-(aQW}p!dMdUjtZdth-c`trHsi^` z0N0!dz(620>@L#%?a(Sw-E}v=U0jLeR7@`@vZh1?9w^lIeWn<$z_7EKyp}MgT$5k) z>~Vhu{Q$WP*HnT@xjE^2Ahxx}|7_i#=T~h4HK2S5QAz?SXi*Y*;%MRxReU^r+=MWge?&(ONoq$f~5v3kQ{o2|lTj z#}p|`n$WIOBI6V{?U|l{Jn9uTBgpK%wP10VWPk<6Gjm=f=9dGJH9WWkQ^G^F zeb@vPN{0&knuLhY^On;=H4|~`JsH^@lH0S|WjO8eQDvFnB1wB2{B#60?RjbNao)t;OnCC$^Ov zkB6tH*);TcwLt&+_iu7-DX9Oe!4XTaF@RB504_f*S`n%YqaV~T;YAkCn0|xYZ#J7sotxe0iE3?ky zG_hEb*Y|1pv2yy*NOh7c&allhHa^7ZPnbGg8WgyV z=PTCuJ^5pNT?&g!*i&YlcJ*F7x^s4S^4r>4k&&OQ&|A(EfpZ({u+v0~A`X|`K9rmU zH8MLWFCPWs*LwShW6KH*@jOIsWC_pAlRS0Kc-XN+3X+stzvlU#0!e{FFHXpJgR8J0acDeDceVHF5$REneyo;Co z7((Jj(7(>ad+a#0?3ai$Q>d@?#WFh}-euJhQ=-54zVfeW*x8Yk9f*+X!437gYKN&{%2OQ%t zcwE?a)40HiZ;C1N9hxtylVUDsO)TgY3(8ZH`DNHR<*C0`h-nY)35Gman3s)gnXf(r z_*#Q~-A3KCHt>3We1V`qZ`^hw(Xb%q7B{f#(AkD0+x%^m(kdVFYw%S*kAH^{%*A8W z>VBlxNBssl7Ut(7b1dHALSsTR>hD{*!RapGSFyf*!i3-c3?HgfByQKKJ{}WZL63w- zC_@@!Vga!H08%O=Xx5|K?1e&!j5ACbTzpGyuMzCufoCIUeop)b%0hq&)%u@IJI8nW zcd8&)A3TJXI<-$1RJ06Rsst#w-D|m4Ze4VVA*(!|3Ax6LiawCf!9f&x`)+OtWG&l4 z@W*VfBD8x`YlyCJtJLaz8AC!S>A*FSm8&N7brEiH9SQ?ey^LY@Q$^-t_YaGnVvZ;D z;<@I!9$cL%u2ct&`KXsk?z7!j<`g$D>}hrW7PT2Z&#`lShY#G$C|Du~%XkGdh`g;= z&amqeonH|GzruPj&>dZ<%Z@!Lb@AtxGK2HeZQrU&9$D<<2G3m?cZ0ZuFCFVaMH$&dyo}V_KJMP1+=elI-~ER_ z=Y4fH0iB-i`=H=MVp6Trk>F#l2U-OWb_C~ALaiHEl!EQS8C$)Z59Fo2dVM;}{ zc%g|vFYU@ISZMEdFs`$2=C%rJ(mt+MWUb2&%>eV`+wWIHom0M+kK`HSkA=rGWut>` z#mEwLSuJ%diOwEYAKbMDQl+$-5tMf3IEx$^+Mbz-IHQ<{D}iR)&E$u%OwWE>1GB-o zoEf$_6S*4c!V^xVV9s^leG}Gy#WL6(KJyzKO=YHfm$F@ZFh7`*|Ew*`^2xq(-4c1Lz`g={kMA6vN!5RAMPE=(pA zoT*zBux;$0%iszLEA>>wUusx;s0E@b;3$f>Z>Nd16tlTqRVN;D7<@K-`TBfPTG?fn zCt{>5IgG2G<1oFyMbSL)<77gDHiieo-5cEQ#U%~k`Rr)(L0@`wj@P*XUGw3xf&SS0 z%AlMe3-N&H_#FKgz@yHmCX%{k>gJ;OlOGW?F`p?LE*{Ld!BmYbb5&4{$TrbvKK{zP zl!iwotxxks-K0MoN{jNPt@)?6Eql8rG~<2`qtS<5y&K^HT%4GP{#i4->A$P*QncS z<~NI*O2)C71&icAnVau!I@xrK&?$D(gqin#Y!$v7NscRgf5!}HL8(1>;Ka$4{4?o4 z+m@aQ5*ns_p)^k0jQ<2f%dO=2Z}|6(Qk$=7uRxg3KV{9ay9*$Skqv#=rutc(V3AyB zH$+4#t@@FxFRIzQu$t}CVHbvWe`VO3Ybq=r5;mImb;Tv^6~GLDm%!@btilU=R0*@! z>XY{oru*c1H06{2T2K_}iMe~RyuN?-U`|i^Wz&U=e@ZS9PslSc1j(aV?uiVh5k5VQ zT+P?P^;S<4#^U<-_6}!gF=D=Z>!0e1TV7A7JnKvn^Xf%GwdEY$Hu-qcoAAaQ_~L0O zqDD^4eYmc)-+7^n6|mDdJ084wbZ?xz;BzY0``Eg_!ha{fRKd|^*rI5}kgTswWMAHY z%+zN~fj5FoqdDLn>&7-yzmx8I(63=gtnrhjTaSZ3P&u)*G(ypLKdrxg7++}@dacm2 z`AGjxtnENXZV}@Ej8L|@>%Dy~$g|v4c(o1O^~WZ9!IV_7y&sg<@3#BsE|INH!0OLB z{73@^M$;F*&`il?iDN~H1GC7bv9wx!n6?HosOcCut`_EPb?a9!dkMroJvhD?JDAJdKzfVh3zgQjSMA!Dpqzie}Sk<|m zHqQEB<{0*~SO0?MXI7R4#-q8wevNlV2J;G(C*t9~l9TzCnKK)ZiSU*N>%mOVd{Loa z2S86rn@7H?ICq!mnIsiq^!uC_SI>)~a(kLJYEC)zoQjr96zeDrh=6M}z{-tlLhdYS8!=@LD! z;vKG=0CGg_E7h$QGWsxQUo`mg;JnbIb?RtrF@FweAS{=tyO-G3OGIvFM4hiW!+L4{ zzA!kx$v*NvPCREp8LgftvA=e#j8AuUNh`^gkAmKEWYBy9X}*)H@Ew%QZqDq@)>H4aoyK9%J-T(r#}HPh+ar6rL`OzC#oc^Ky}w% zt_H8n6rfU&rRUKL6h9OrA$zW%i@}Qm`TfC|MV3jeYK-4KApr$C7ISwcKx!trpl$C zGrf>b0_NA?S59u}_8^6`{VzE!v3N83s_O=+2wi)1J5OOso1_TxhE5v*60`EaBW#-- z7U43(&WA$j0iw)C1nTLF9NzYQ3DNwlCYQES$50x-*u`$zv3r{E1@;al;jv}#`!XTj z)Z<%&%Sy>hC)MDNd@)?Yzav>t|i8&)U%QXi&I zX9;Mp%Al4G(wk?q_ zTesgnc;!46hd+0$Vfyu0jy3>KHV~aLa*zNr{08^8T5TTV`P8a+2`l34+Wx%ghyIPZ zp=YuI#8CW0v7^yHMv98`m@UG~KC-q3NeZu4DzdI^2VVhrHJyA>!Vst-{0`B!E(F#4JfO<&7!3=@TL15`a zA&rwDBG^EUWlB{*Ro|m0O28<~x8Lv%#L&=$G@whTY}n4Gnf_=;v-Tx+VQeY_Qa0=c zJ^hr|Yoe9wN6!1fjSe(-Bgw)AS;C^EahWE^Ju`6D)|dTKb}}OIP%2cMf->G`D&+VJ z_8MV4jmmm28L{+rxw@-r3$b%2Ax0WmEEWS0j*FVYcng{CK_(np=c@m_entIP znyDhB`GAG!U%)o$TkZeCy(<6U#iJpdaQ{Vt+5dmx;meb}>i-cO^FQnhA^$;e=fVDq zE`!$uN&nrml61@epvxK{Jni2Gi2q{7@TX7K7}O9ToLU|m@+xS->~9E}Ru{EM?r)%5 zrJhvwpAJCia{_hYKe#rC-WI=NFrtL%uUY#4(trA|7!X7q_{#AYmJQ+uq08hpM1QL? z8bbPp((|?)@)vZU1SR%j-11fD1Us8j{150JLK;}BSM~RZsSy61uo0s0iTBWlJj!un zYg*RIgq3~}a7!DaVX8+8t9F9Fi~QB7yTNKi4g@NTMAnvteZe!xb)#fu4C_<~q&%3f zEjG~_5 zJ~mJ^hq8Lr>aQLBdDnHS%w*ftr;rq0Yp94-!o({VM*3Nx%Pa_M6!Yq~q(J*Kb*EDj zCDCSorLjU9(Q_5I6DfqztD}=m!#pa&zU+$EIBFfcFA16tzBf?MH}WJNOHTey6rIc%f%CI`>+l`LYYj7}2WZ z%5;$<)?CU#)ka%jdK(h+>ez9{p+-)2C6iY%k&QKqs z0~9GSY>c8B|CJ+s6+1s%8GipLb(1S$1vI~Ks&^vVeSs%RKY!Hkeq2uRtgA<)USlBg z=&6^+zz9v0lWTfOv>LBa(JK%e_~d7?Bi*Y1dLqm^1^g0A7Kxm2e^Kn5;B};Xhejt{ zwhbkJWk?w>RD|A#V!XGn`4~47f59rsaXXvW%y0YsUl`*s~cWyCi`)o zf2VkC-uVuY=zb#lNfOl zY?>M?XNT(&osA$Rh6(auBQ)ZACp-$=at+b0`#Q&WEv7t1QcJ>^Odv%Nm2J~Ha?8}w zRz+0(cM%)4*gvMvi`a4*#5vi;&MX--4#ZAjH2TG0Ho84s$hfUb28eys7>xanA0`ZaAwy`C&XLgW|%LN&&{68uey7vJ?d=8(cBC z%)c#6%9FrGc>jdiC@s<>o!#z`-B%(TfM9|P7-e>G_>?6hf1HiXrKS6qVO7G@&L{n?Om)TdDV=RnI#Cf7P1`O7{t0OH#Bj$O+I>jeqi6 zg8W%F>Z4vHF41xET~pBFgR7*?R?9^(k~H+1L?w$;LuqXFk8k3F8SL))8eeC0d81u8 zc&~ugR#(G&(H02Sw#Pk}GA}wa3@>45uqo_B6fuSVJ)7HV^`EAe>Z!r{wpe?vWipY_ zV~xpkTdOr%g#i@?f@GR4?w3{V+lwNVb=%Sj9fqx}sSxz}+9B=4G*sZ6898Wv(W0V6R6 ztg1m1gpY&wC6Y=MJ0z=-v83QnOk~NYL9MQirYwNHD`*;aYOEtGn2r zSed@Ug#nvrNuqHK0-)jpbv$GvS6-T{AtB6+VnN5}uG0cTOuk;&BdHp`w0z0}XNhd+ zoO2QtRVusw*C?y_?>d!^-zKoPTg+?DD7T)P^Qy*a8PD6c>ORmt2sl`bd!_7T+(g7&c`0wk2pv3MvAb4PQ!|5f+UNge9y1Uh7*j#Bja zNzxcvT>0;Qn$u*`tQJ)SYc}RcyERt(B>pq!3-4J1duDqKB>2vi&i@YNGJ*XQm)l;jBO+wtfSq@PoR=aYBS zB~R&bF55PdYcSM2)^;%Vn^Np*9qcEtF&1?0jMVO?vVA_58M*C(&;2xCGos!5BoL*g zy^R?NiJym_seim^felCo%;~Mtz+D-Y;{@c}(AAZ^IuoT}Qm;f$vWl+_q_;op z8Y~ZXF|o1vgEWndJ_-~Abaj_+PaWDb-2sFI{Z<9LaY&hyn>yHU<3;yFCf!;}ftSh) z^YPD~ziizWpm>otUCrsGUGy1*$z4PN55HU#TJT%U(Y$$PI|FK6=43}_g6HzV*smBW zvl8Rwg|0f)I$6f=x^C{e_WJ&~2M>J-%0R|@#nA75@}_L|B@nXAT)ua65qJrp8+wN3swvh&=!v@xDLF&skMa)x}7kJRoBCKGHMeY%%6CV8s{`#>xIHle=mWD&kNJF=ET1i$pCeQ~ zg>SVay7ybE`MA0K*4eO*CO&)wo;_#BLuy!dsOv@WgRPhBtKP7Z4cW!SMOw6AFV`we9Sh*CMhP@(cW)!@5oJ!-XG{}e zF@%SMvt9lcK4~T3c4y$^RHH%9#IndXvHT+xIwUJ3Bt+!B6Vf!|-skZ#-xeJjB~6y{ zja(OO22Z9N`Jw0i>xL1a#I9DqNX_i%!`?}d`lvs^;qn@w*=!kou}xkoLpd_|4blmC zFTLZk)VY~_rsMq^zETrx=3~!WXGdZZ6+&ZmCc&UUKI|vPvTM4@7xT(hfjn(*58+vS z%GpjjE$aofJoiiJzg8!W4EvjzZ&|sDk(xgj!?+3i(e2Y}TU&TIl%?g~jR3oOtIQyqJ^mhDbO6~;evChI$`I=!+)<$g*93R3BKP_Vz>#g6uFgIUlW-%*C=YujUM5y6^Lv-lMErGL z%rL}6M+eI8?~NZYXD<>U@-5a{8;;N6#US=yq6e>^8IhaXXjRXwi9y_XIfuW>7`D2P znl*h@w1Sg^w)r_bJ9{SJ9u*bkKtiw@v_%?T(OtSWZc%Rqocw)_kSafC*F=|EVFd&_ z8&+$0yg#=7U~GaN^>(&T7Qf-!gWF;94Mwf-h59t8<$uXeND z$t8&z$h_=HhanxdKL#+O@6e4e^z77Sh z6E7t{x!FhpnM7o~&1#KdPAHP^XG*zCZGSX>$iyNQT2fi$MexYzH(K3@$(i>|wdk{{ z2;>AJ*}3ftB-@`rY%Z}eHat*qSG00l!1ey10*-QV$;Q-px;*7t4IAVRXUYfiPdqTd z(ob7hVd5q#s5}e(zs@5H}I-HV@ZbHV9&RSzNWcX1}RUE53uA=Uhf2&ym}#Q7Q%Q799i!|%aP zLnBi>`^gBH3dzFgz@4@1u)hh$R;?!|J35)g<4t7Fdgyz9&S8H?XhXdR54D!+_3ZhS zdUMenG*VvXUB-%!u-!Ukon<8x*Z*x#q0+K^qPC@fbAH$Rup`zfOPE)gk3kzp0G|HmvHcYxl!wR#tYu z{D>OFzk&dj*To?HDG01hNX@vKTwHzgI-CK`f~D)P58>J~{6?YiDv+mp*-eTSnjY))GdoIJ=P{bw0B-FCx}n43QjY%t9|g#J|{nDAuIj<1}}epMua73z5TXYzvXD5QoHnHj=7ncX!^*Wt7%Gj5Et&v*-F#N=DYBhu!$~@lf&6U zs7IgRV6je!COsvFR39iPz}u!i&Btv2^R|N(uVa5NIqdWX@nq?7p6+5~6tc(QG!7A% ziJ-~W*L3=R`h=;~pgOLJqZ!!kU?(0bE$$;Fvo=nf-5$5cnhA{T8H|jKf*c&lUZ9Hr=;Ux(Z?E>fU*Dgdd?d~3 zaSl}9E(wJR+G+Mnyk!1i|Iiw+SW`G0*IoaR>ViSDE|s)*l2-|v2!`|sJgHbtu7pLK zVcvX`xjt%1J9xL8!^6Gm0)bmWYD_PW)A*c@VyH!0*+R*lms?~)9qE}V+YvggY$y;T z>BvL^>p}0YL;~)la?JvmgqZG33 zIXv5d|1fJfcIPivTdvZDWC@Lmf(P1eV@+vQVi79l+(8~AJ%5u*XEqE3hU4tg=dnoI_>a1B#A8pxBONlWKjoGf zGAu3#9eyQyT{i!srgo-o(~~#QMmDgyH5Ejy`PZ#c8BECK_rPd!>Bo#}tu_N`T{=%R zjFw-mh8?YM_qXvEc+(x7{*SJ6zluU$1XJY)YfY!xJsoHA#V&_TW{kVD13?RC9JCIo z(^9uDX7a2gsKu;8CD)og9cCCN42l4vP;b!vJ1FE4_OC&&Dst6TcWzxijX z#BR<3-Uo-Gx#?Qm-hs6rD&`pkFPU1w(_fl7U)E65yazU+^VYiVDb(c4U z{NnTYEt~Y@l2&QM3ko!g=m=z^*ieKh53zbpSa&U~^%=EPaPzr~)RqUMaUOCu10R5q za2P`Yzeo4W4)+Z^Jela|3T&mPi2Py2AqU2yyf$=S#u&iCPXn#;0^TxaZMLi3AED+t z!N#Vi-+_@AKg7IsmMSzWKR`fOD+alOOl^xuP97M%x7WV3v~+ptjLO`pTccMEkBGQ( zyECo)G0)|38bMfz;i&$Az(?Ury4Kg4&7vJWg}{}nfZwWZ0}yCXP7ychvF*lht8DtJ zbm}!U`-($tWbbAmU~YJILWo~ZBIJA@oHZ(k#%x#*f2xs+VYuB}D$uj$cEh`A+KsRL zVW(E!&s{45avj(KwkgEc6)k{whol!K;#7)#$5pmxEcc~$;#eUn>h5ekD>cV_6CL@b zF*qW>m5x}gmgj2>bVv%N<1%^bsF_}KOk5l@$nyN|VnSA}q0VWU>G3&jR8&+Fv?|Z$ zOQ&P-I7os{ufBhu$qRgvBTtRP6|Qhx)yYu&6)I7zvC-<|HkrvK;@_iCuJN0o9Tr34 zg>J08yc`@n_+2Eb|ZP}Tij~%9{jr8;#B7g zw+k<)qj<`~LrEF7-XFW(V&r?i*2dCIog*jkIv+2Bhj^O7-5-I3fP}=r!g4SyE2?Z^ zVbOcr?6?|7^lSri)}rCKu|qR6DwTu3H*33fx}FSC@v=mgUoL`zTAhK{*9Vj9bpZk* zPkkp?fysdh6z0Qmh8=hP$VB{%1`jRMEe@uu%WtnTF}Rur1|QmsIy)z<8af~M>(AHy z+>d|yY!7^a4h7dhhWvyA_wZotJCwcL5KsLcXf2->I$U;k!bwuA0%LPLhZNqy&7>XF zVgxa5TgJ?|O860Peo0*{@t)|X{#9XImVGE@v7)hTAlmND7;mQshWBGQ_ zQ?c4UzmzcReq`G}ygvU%U~b}--7&xXy~*L3cy(F9ip7$RD`>R3T0owF7aN3TD=2qm z<$mr_HPU)o1@!Fg?Ho1^|+~# za&tFp*KUwvdUIfU3;CTh!p2QZ#B@F1b=`0Hxg7|1*)7nwCK{@_1N-8L1ezU|>wT{G zL8oF!{POa$U93ELq7EZ=p#0~}Bjd^iMxF0l!7#)RyUEI+t!w*Zf}58Y*8o2@;@h`A z>s;N-!@`}d?NkPB;q{j6Zi2PE3WIs^(hR^gmt z49DBpPz>`Jt9YEK939mJlw2W9Ofxk=L*bUjYx6iIIq70t{-&~jH$vi3Pt%sAaw?Q<0g4IGx>P#=&9ZsCA2MS8bcyd5MV&KN`?ZvTdgPx|Ebf&(R{Mx_4y9D6(B15 z33N}AqfyRfWM)np-%~5Uu^F4axw#QxF`{Kzq}zh;xXy;Gz<2U9pbHXEud9r5u0b`d zYl95~%f^c>S*Tp>Y_(CX{Q9-YUSzjtY;^STYM6uzU&+)I__KT-o5kn@j+>jC_2kod zI06n(wLcPtL?rN~LX!coHi85XA7;&M|BI30WMv{F=<)YBOS}7pi;P^FK&T6a#&b(T zzjdZnr$q*@e6ebBpKLFv)UM6P{lba8ZU7undjFKFa;o>{lrbJQS%W7b!Dl@!SIXma z>fIsb0m=BZXj5z=T(`5i$SJ0xMJpz8sG{R7`t*%f&two)L z!E#&U`1dPQXr3#>-8wck>mWmFv zN2JKr@#H7eLg6%*=RQ4aGLs$Q;N>)QbadLa)(y}c*-rU3p0t*SGp704@(K#~r|WL} z6L=vU%}@({vguL-Tt-AsnUW z`Rr#f=_jrH+<~=8VeB>o;W0&tr&W^j6;K-(*{?@#<6(I4<3)){O!glhO0GofecsgE zq>)8Vt@H%7pQg6KB4KKl@{QX|=D^6AhZ^mZ@%6fSHh6+rKrp7avA0!sk%)f?-%~X| zxniAJD4Pp`hf_-gz~E#@d$2{581|IU0@?-S?AQW2GvCv;tcD*VKO2U8$K_en0e1L+ zN`sT2QX>H!a^!Dys7k0ISjhB%+9~yee68EQPN$6Q_mMp4V_`ck=(&c*CK<`yIYHYL z_uEP||L7*O0N~t0s(O@5^@w2>d02!6sLJio|3Vp_K)CR8>^=*8B=^uG+;s_WbKyyH zRGy!N_EovV94(&v=A+hG@5R%jLNrJH8AUJX6O2tCs<}3A0bU4F*?wrg+`_5IyET?X zang0~GgPizP>FGxAOW-gxYd;%1c|^~T`uHOG9?y_>$KQ9sN_w~KBPn$wq|NG>bC=^ zblLdQ5Eit9^woXQL1hG6BJ3H}b}@Q62oMH6DYibI(zL&>H^|R!jv5;dU_)@wtLj*2 zV-gZ(K#sM(E$GdE<*4yo$nWN8UB40u6djx@i@f%pPxZkgZ1=u(L7blexU-aV1*en= zt{5^b+3{?M9`a{xM0sqQG7k^SepTyn*<%yq=4)1BZuMF<;3E#r&DF2^JT5Qu)L2>{ z9N?s-9Lvj((`IQ_Yt;|Y2EDcUKZYOf=LLh&gLXJ0qgtgVDAEeJ=(^w1zpMn|g5>08 z3uCD{0v>iy&S}j&fc=f`farN4%%G2|HqMucg)%rSZ^Jmofpn>Uj=Ka@(TkujZQ#ww z(>WkF+UH@<2sr_j>2_N?GRC;tPTy97$_}zPyKh6R82QCrFTXaa3*dBR)SMMZAFxxP z?`~1wb|S6JLcMbmKgoBSw3|H}%`b}RLXCcS^`2pX3y@34AiupDPu2mIx(afGqA*rK zR7zgS7sT2dvzHGXoVys(bRTmY#6mtb$VBS<1Z)X^@fNM^J>#IJC)?d#UH3aC{jzN~ z5<8xX+H`TR?|lXC<@2@lc3OsveCr4&p3WUQf~$2I!k6KF6^W^JK$|gF2IPIDWk%Gd zv+{#=FZF&D)aq-s1xTxk8;^F{g3lOwrcum{h*fsF_|OUhpI`Z1>?fs7W#~9nXV|L) zoA3z2s|P{#q-TrRm(^&Sl49!c_r!u$hd)08)oL%1m^c$8p6v6NKk`|I8F^2ZAN;Z> zvzy_Z`ihI#9cm8yQrHiXKN#?m*t?`f{QwIelgA9)IhXq+BsXU_?#A`DGJefLg}MS) z2%((I^+n>OaHKsYce`_cFtS0mT0gE;arK2fYC7QIkWnp>-v|(BpY7*SFsH*C;y5()!hCMYcHlR%q6CKH}@Ew38x(6luUla$X zd+I3quS?p!ky~ryjThRyaE(Hs34TJz!dMFsn{I*cYS{7#q(QU?=TW&NOZFi~I}5Cl zcdvJqiZfq+umojlMG7H#pkbmS743Q%9(CA$ldV5A8%BvC=Mt+USM2pB_L+wE55*#e ziTG`MX`HXwFLg)e5TVAGeD3H&o=5dBYL<15NTPI9U zJ}@kPCJccBGJ%l``YY2kF{N$O-g0VB>Ruap>m9c3_jdP7jc9uAtJw2z?l_!^*PM&{+!t_hjfWq~bp4YRXSb`rveuNCx z1W+p!fW_X{wrm{FbiWqSsjJpM(7i;Zf~qaG-RQ0L$@_IQk8%f5(Bc5lClA60--@Z+%b;P3;n??~ZBTl=3i8?m3>0`I1_I z&kuI2OVG1B768g@SDkytmqe-S?tmp=nn7fey#mR8K~Kq;Oqr*Kf+vK65|I#lDOuL$ ziy{h~&=eW2W3VJB@1}wQKL%G?pyopjGQVfH*=$3_E|r8V!vdvvFUJrgd^jzu++{H%Z1dj z$z7+hH5_j^nRz0wkK21pnf+_Q*NT`dgpRQQiLN&`a=L9{CmTtWrp>xbNT#w{vb3pD zpeQ>%HBFi){@00nI*YMz(A&!c9LBKFQ`w{y7hWtUAiWPMP^Y?iZf>r(w>M+H6p4hd zLcNsvg%{qOZ7EWXmun!lN<$X=oWI`|C(zokwQmN~G~`6lB*Edd$kcoorOp3sY>EUq z=x$FrBO^mE7G5&xhl%%2>|(Nd-2U$F?g7ro-tSp+;^Ud%oPK&HhAfewjdJzUZ{Nrt ztIt}A4rHDC35LrS?2?yXjzx@5L`+N+PkwxWTlnH>#~HSq_}hMYhZsV*paNhtgSl(?#{8LcWcHlh^OKLW(c z?Y?;`Z&@EkAXoXhcP7O%Lu{4`yqs6%BbUZoBNNi0Q+1yd;2(x)W5^KT4BH*p%+=Pn zBel;mU|d&x5kGt>9?TBS+IoJjmEpIcc!P85ENfU~R+Ce|&P4zjWSLzu@Ucj)dc1+Q zQ8>z>`gi*q-?rQe`R(y!u5bXKP}jDFRayQB@|nQV?cUK*dO`3(&1xKp2=rzh!q@6w zZ};mw{!6T_S0jlOi?xRHc3dye^u@)Nc1?CShl$BF9}j;P%Y^H&xjX}BJ-ftVeZxtN z$#gvWjO+3sO?C`^pWBXEP{lx(XP+)LOp3I(8Jtd~ak3xG%4@Sh_E_bA|l+`^3e5;l@VH%zXd!39MmIO+yDZu1Sw+fRmD!7j*ro zw*)w>bY@VV=zmkG_l|ra$IoQ;=J+0OHci&d)8L9 z2UW?054Hmqwef7H#|k2*ImKv1nWh33`!Iyux6D4zuhcPWtr@N5 z@y5b~O6We(bFM>P!BuRI>(K>Exb^H;$sZz+;DhNM-jek3R;!v~%#rkCnS$i551nN? zwwkMV{b8OaSdKy8H`xm_E38>DF}A&)MeKWAenU1|jKzn@PBkYIE~Kr&qMNW-Ad`Eg ztT&o~Wx<9na!N^0&k^<;l2&!~j764EbyrlJpokZQjC}&Y1PS=w=%}hD$``BAYg!f; z7nlMYtS67wz7UPdDk-hk?FguVA@)11si~+em8%bz=K0!AyQ&P#`ql(qONu*;lqzm!+dgozP_V7Ai+NgXIWM@Z* zR5vwMeSf>Z^0i#3(9H9%=cAT;?WYtaq+G*E8n>_3A}{(<=Ru?P7FB25f&Prlwx?7pn>?rQW!apAg~> z%dJ+$BeAcS8mIv0KZHd~6t`m|;MOBBSk8JMslSVZSoo_tO+dsY%wbSdcbHk$$x z6_xSxRpg(Ff(Z_l&8F<_3P$EeYV5#D*(s=b<0f39xZ3h{%#qR2XDobSTME?`@I1OQ zITIBm(U)|%&}BdHn*+G2wtJnI8*$jlim6ie4OHoYTr9Lmb>?z9Y2p#^CnoXJJ&YY} zZS84{#hE59NC>f78*PPvTTRVyHDA{5V=3-P`EIP|Xz4Y%rrT{>wyAnrfA4sp4?os~ zcpA0?OD^CTH$D=5UE+0DTptLEt~hknF`Pfq!;aw<(WsOF+6o4`ALaJA+R}1PNr@TF zP{=mf&PwBEv-jmPn`zE@vScBJm>4G9>iv4X>D1p!Dc(%PDhIx%VcK^!$ClHxeKC6y>=W z3l)s`{$GB8$<-L zU5W2}&c+kb4-JObJAgUE5smEg+F#a3*s(wQ1aTJ7J1?;El1wgxo8m6v%YyWUuAi z1qJZKuBH(FF~%tzU9Wg&YZLeedJ?lAn3=otIYTurgfw=1NrZ4hxJD)5IEV41z*!z& z`5qpax%+ilxJ$hH>!d+^A92_#2w#M_k9#nAjWn+R@{&`+5wE#36~6tQDT4+RF5Ot!;P zyWPRnC9t5S^9R9qqg!C@)#>%#22kMBbUB(m%X-=F2LQA*x`(x*sOZqur#sKDUL`L^_n%mZR#X^$mr?}w@x;-OqD-(y*G z2NuuU$m-U>fz_Zsn6Y+kb=|W>qlR|pBB3!$^E4JItE-T;3v{cUSOXO(p$C&A-Y9W{ z#weZK=z}?oFRp z$YJ9;6f$w2oaLr-x>Du1%uLT~0Fa5p(Sj<=C@5^*dcU6fi%4AgbAs!zw2COpUURQh zPbV4-2%w3o4CBTs!gb$hsDF+l%_6VGkp>Y&%CjNT(0cM~H+5NUcb@veA&p zs+M)jWF_A|(eL=LBJB4PGk}5~k;P?jQm5+=wmkxY;P0pNx<(9>InqO9!{zuRut!rk zAub^i^Y~!o?xe}_yoCKrmi;!n5}kZ_Ngp=&r?TS&Onz+GCF%C1eY|Ma+C^yb6*bA; z)mw3qq+VM2+ml85R@Z-*&zH!%F@t~VVtuv)=XS38?y~f(?dZE&8R~^fo190Tj)k+u z=b5&JEIONGOj8?Jz-psv1Wq0`W9^%L3N4MHZdS3zvvmEe(vR$m+1iW|Vc7~0)zP1Nf9Ovtf>akr&ILg#Hp3BToS_}asSN&B z6bl-|_dC3riCmnFYNa=cfOPOsqwt1oRAq3rj0l_9A!j2Z`2Gd{yFYkqg1%plCOvvf z>O+ZY;m>>6OQuVo?<|~i%faBQ6-h_X8crW>sG8Lhf1eqHJG{)pUJ70R5ZSOnUs(Ki zMc;%}rg@?=xOuM-7cm6*MtBazCv*FPjZit!gsM{}4xorUa-2?=*4DHY7{vXzdjsK) z)v6l8LSf+H0ZELE+*haFK?DU_SP1u7dpoI6%|Z|3YrzX5)_JLFW|ecbCq=Zd8k@2) z<;hp&4ic%L^#_a@+AUFv#U9_!!1;b2->R zlq~c~L{&H##JzFmK-(ve?*Ni+f7Q-6~82K$@~51y4KgD4%Z)h zgoqF%3-Er>UjnU;me*y?{%-U^dUHbRYCW`5$3iSTKkIpSBA|y#kDMTN>Jn|XFFr{O zp{+&L5*sTi#nGfsNZ~pLLuUBNf?Zdj(%%@vsf0qJQoaM)2&^Z z@~Fx{+SycipqMyQdow~FKq_IzkcI$<%?;8VmOZ+uENqs2VI4J(8!1Th`6i{noeN7I z!8vLKq9LYgMi7*{v`iX@VT}qS5@7zlcrWU8tnBQ}Vxm`sm^UymP)e)Y*M(_ zn8=Hpo*rEkTZ|>!`{Q{$m5n6oyTEh*?@iC*g_WU6IZ8t_$)oMQV8hkFc39pS*uu!( z=l3&i57=T#zQ25lh9r%W9?p z%i~mG+h9aZddxs!eRfof>Ih26rof)+G@x4YwYmTV^=PL9@_r!IEnA`4NxBWOUdz7E}phhj8^Ez zN|LLwu?cP@xY%@i^#vmYpFZAQtk)U_N6_KK#>N6n_b<~)?XC<&Mk`LdwWs9nacqtQ zlqy=}zqEWuiLeX3&~5|PzvxuTVXhvW52}N`o=<`kMAS;kUqI;4w2F}%MFkb<6we8=WSt0e-RkN$v>B$?T!l)pDS4o4K0THKLvTsnP)D#Y8cl=R-2k2C6){R zh)PnUpa=yt6AK&46tH}bB^2r~y5%t7;1^Pk!}IkU5DlQf8)L&5M_#UwvJE{Ag~ADe zruF8Lh789*1&NA@HJZ%`SDIi9oUgi$C3SZFnxpi3S#IMWq#qo0ED?NV& zv7qq?qQ?XAdlWZHdmkm1S?4-xy;=~)~L>u8QzF9NSkU?YgW#WCSd(A>W zc^OK$bd@K-2LfH%Im?!|vJWP03-*P|EO6R_O|6EolswUtyh zzOGffx2J1BCe*4uNwfyN2vkZkE+D$lc%LoH!$4+M_1_&gJ;kJW1-v(#GMJ+#?{D=} zvy)l-zkLFWR*YC-3>kBYnXuf+2asOhOe6!T}yBgGAWX)NbqValiR2R7>E zS}v?q*L>+!)pr@Y=p|JV#>f@CdOu{UdcKxbl*l`TChg$4a}IJu)D=(`sPRu!NQa^0 zaxMVrB>$S?;eJ!R58;TOOG&3nC>4t8cFjD-7oCdZADJlf(1(5wm!Pgfo?9>>+$GD) z=f3S083(GjBD1#ZTJX6Vc(;XKFB_%~-M2p%U-wfymXbx0=Z#$Km9iQ)0$xzO-j zjnA+cK`2dO-~2#UYyO{o$xHsCvg0fRPr5M9U`R6M=H@0UlQ# zUAdnQJBAg~U$IaLMVjJwfWoh6!u6pj&j2g|;Hc2;Yd41kvkA)i6ywdDRa*BariZZp z!6-2P(1k%c=-=0|UjFoneq$rk&nrcZEB}h!D=A|<9`iA}-2HKV@ry3kyw7U-i=I+I z+EPkc+CuUPK9F|Vfgl&CyWIilM9#qEeiqB9cYgBN_q{tP7zz@iHV$#etiBe>m)pTISK!~? zgm_|p$vS%*uN7&Tc_E}h9Komex`man7zZWDtV&{O=~RE7u*q8SxDx*CknMBN7ViW5 za8}`$w~W_ld_FzhBqHRTTx#5%r3wvE505Fu{GmHw4Iy z47Bi&eKt@?lj)!EG^LrbME^{O_S64FPH!(%(u!(q)sp0>3M4s_cW&=7BuGBGt#-TO zzodRGTI&q)-%SI{5mZzIJ?;93zD69iD#=2n@`aU7t!5}9Y$g5NotjVSfvUF-U6R&Y ze>2Uz8C2PsvgYKD7h{2$bC^6QcVSX0`u@GHTnoZnbXq)wmAA@ZBCHWlC1NefMX*jHP+Uas-Ah=k5V58?^Oo;uUAg z0{dRea{|1&3zAUU>0b43hBeK$-kkE)SKsr$HDbe4rZ115r)p`mBBRD7-H_qFm4+qy zg_5*3%D@{IV#6qY^!J12DAKEzE75ejT<1xT;I8gtp`&BgL1kO5Hd*!f_*TE)a=2_( zZ*~GgA-41hVi$DSf%^zF`fRG%AkgDVE=QngngWetLz`!n%4JmW6`~8 zi8c;BII60DMvn6E6}dl}nvt=~?zRZf-BE6su{$5na?rAVsTyhuZPctl4ed8#^?X<^ zetv#doSA@Yg(TFp3m^Cr`O@imNkUtsFUnU9{R+%Wx1#J5@(7t!Biof z=P*jbDHQ>%Ta~$G!w2HxNT~knKja-tVy@W36p$C~M0hQ8Z_{COA}|O7v!QID)?Fu58!sAx;GGV=Be>RP=YLRP{VNU9 zX|~Q-=HmsR(b~-y0J^LtFE1}60}oJUWqZGje7wK*;2izykDy>L65`_Zow3rLN+c)& z?>kQuJ4KT8C6+Wy?SH09zZ7m?A9acknw6Pzfl-$VWQOnF_pK;Yb$N}=rUjY*b(7lGvoVg za!q!dLOMO3XJg5N9co-$+BAiOIV_junK%#prt z8rXjbb?p{-KPRq*o3FsGU&w*7vIr#&QyAKWjPXF1 zu$~l%5&$O#X>OgtSAVF@gMv8}RR?`v73+azNLx}K4CS}i>zdS z)QLjd80G*O9b2kgHa#5^5fO2SB{20J2~@4VE~)bxvH(&_wJfT9u?hnnbDs8>ok7X= z%1kno#_OZ7yHs|*Vm!cUt6DM_6=((_C~q(r=Nr5`{69qzk#%qwaio7_-VGew^H<4l zjXp*^0E-Xwp8WLY5Hrk;E|Flb$A|FnaIj>c1V}Il>#YvO0|uZ&R;z=(81ncE819p* z_}Kjy-3H0H9kwJCs7iFp*E5IN1e~ay!6?4D5ASX;17|KOi`;1W$sw}VG_Q`RzXWSF z@)FSEZl=1VT9u|Vj*zujqQ2xpah)7r&(>U_7S%19>K)3~8*;)M>OG9h$teDvv}*j? z{+q{ZCqTTCQtB02`scT;=1qVKOI^-)M^d1rlFw>!*(R05k@u{PhA@tgb>-;JVWw^4 zkxm*U=?ve5juJVluBP6E1V#UOif)y)eEmGE_grR*t|6z zZjXSJM!!l(?Qyz-46r#)aZ1E*R$%m$bitVeAVkkKzV3D)<{k;Qd>vBlWv3&n<O=~0ztdCVj}N|u&|TAm9Jn({59U6UBGAZ&nt3x z*ldA^he3dVgnS-5wba~#5uteYgROy_Sv@)R?IC%@v0sw3E%BY0IBYtACOaw_H6j$$ zNhs`0jrK5zT8WmdVRSE(Z*w#Cdw(S5moH~*3Rkvp%e9`v9a+47w1sBB26#Zgz5N^u zb+nrcQ!+El1jo`ii|8+jq`f@;i*ro>l)&cLI zWlMo(*%ZDSSzH?54IXxTcf?fF4kJ6n=qXDRf1yL+SueL}ADbu?v>h!nC;|O)r7JmzIMg%aIqu^M=HRILB!oHeb*puR zl0_x6miy_b&ax%CLd3v61z=nmG;;R4IC`3|OpeXL-fBzVWsI7mM!~vI51AMyhns?p zuKD-*szrBfFoisPM~r5V9XpJ+o&6U?R_T++zI^$jLYp{X;2RAA0fEJ+{dCcO&Y6yI z2TSExf;o{dnVME}+%lw)ck5Xac5dC;X$GVDCC#5^fe^zju#8j#+u1w_UPJp&1}7DmW-_u0q*nB-$+!F(YT~SCsle( zTa!Bq<_@+)(<*^BCd7*I@G$aB>n1tLE>9GNkPs4OPcSJlkp?|1CkG^bLVD>uJhVI& zr%_r9FmUHvxF7Gdj)#D|ItGvf0vOzm{{%3jjb>X~tY$7f*MAKE%AXfpRExmDT47hC z{vR<-a1yH9Hek=n?r^9^z%{g8<`h2|00Em8pG+rx-(d-y?72F?ns)kh_RI;6_FF}J ziMuTtCF?8fAPxzC_I{`W6A0U}n!3>KmO;uTcSL4ZKBf*+{v(VchN6I?AgU zVSd!K&>=50CDb8#KFVOZGH{*JKEyFGUQVZvlauQQ_P?;=zQwrOcfUP6n3$R#jJ}R* z;cS7fP)z?EQYun-m1LRgZj*{6G*EB)`#vWvM20*W^WE8+KeN;%C2v)Bv|XFyKp=ffrJ zw#CFtfQ-A)?60qZnT8`b*n-QUTt)iQK+`qew2|St%)NlE%p8wc&fdkPKlxG9jZbr10usUjSI$fQe zt@8MM-;qgXT(#s>TEaQ?pUN&y*ni2fLHe;txM7G)7{H4!K!d)v(03+LfqMOJ_ahq=|$dz^7Qyk)31SUW)k(y2j&~>r28Tr2VWEG*<~i&xe#-o zng6l$4~&@OpNV~>bc(az>XGT@Y#I&|AJ@~p;S-7mz6lRJp-B|4_ z1Gf|h6<6803Uf>UG6>%=s8{)AqQMvA(GY9Rh@%tHF+DRJLx%3}tu6fH7fgune9iko zcMGvkhkaE1J!*t!g{RJZlq}cH)3jpf=on?j+o4!+Z&={lf3NS`!_CP_oE&A-nVoyoOVw>j+ldLA-e;#L&~9ts{_y4yAUl)L$2)%)|ILz!ARr}LSE zloV7JAedXO7o?z@11Q5GB5z;`il9cNp#Phj+PKwgZ>7)@VAW+4(LR$Nh-g@~Aw=PZ z$&m}uidToC8_euWN^Z%MjDFfA8R3(Jg!Vgfap=sZ6&eqFO6;r|+!o>Z%RZs(`M?AT zCP+|zON+wG^?(1Wjc25mAB-IWA7m2n=Lre51X4Jwe_h%>44wIjxLB`D>W^emc`5O{CWw*zb)~dBe~?x)Uo{?0UgU7(yX==OdpE>vm`GNpi|!^o&y6&+!!B{Q2q; zdMz?}4?(B566%v-VIjp@znl)BWA{K zNkI>C+#RUn!b_<@RC3`jJphl{s+7 z<5mZD@$roA8DmhV3L0iwxVpr@eo=OP;)IccuCxGD#8D7lhc4@pSA zyCI%5?xTJG%XDn!t7{G!nz+Hx>dzpx`Bg0DgQ`qvIYeoWW#P@_H-+8oSi6mekYXxh z`RvP7fzM4v|GWB)5E6k_baeE6q#PPrIFbuo^0HRX*9QQWQ~lBeX-Q!lA`tL6np>`S zg$GRwRA=DsRad+bBO@d7B#ENAqAeDDo$@_DBuD>&SKG!vr6KNZLBIBWA+2Q1j{`S$ zIbv@t8R_zMKf2PvOHN=fLPCx=7uV@JkntzoptzH;p1Flfhgi}`To}F|{i&_7=<*`f zMetj1$pg*KLY|A9a@}Yix*`i6JZCt{5P#n#*;s8ES$4L55;jxNjIRDUF}E?eFs`>;Qa4t?{}!BB@fdF zJ?4FF3|XmguE+t$sm?p-O7pHg4cBc@ZBV#!?7@jV;Tipb`^zLrVc52cy^Zqt4o*6m z-PkFV7e~iCs6!Zn@8v1VuSr3ZRyAnWnn4|Qe1EO(E{&n>T?RVjK87bdNBf!o$Tp!X z@UQb8Bfe>P>f|{bB=g)RLmz7-Cr?(&cQ*l@2NacdPew011XiecE-+wA4`#n;OwH~Tuxu5&=J_$!kBF&M+ukT}Lf7zIT3pJh}WCn%mf)?TZGUfZal+#8UB9eEo9pFG0NO#HbC zN6L;)@eG7K4{w%IDEe^o&BcWhrWUvEA39CqvSTqNfgyf*q&;O)d(hwVPMx0GJ+^v$ zfy=I0$>~1>GHu6O&agKwSPa4OPKS&o57Bf}axDZqvJ`|9TH=Beu_LEJw`VCQE%LH5 zY(6$t$COJM8}v|vHgkPZF;6CeWWAEw@#{0O|HlRVZvtfpX8A4ySTXuBjl0KwO*bxa zq>Y^_RSLKf=Zvt~^3?}1rq>;BWp7-$^_@z_0u?9KaLn!a>6qP`{b4iq3~pD0#i~rt zmo+|oV9F%?nQ~DAxP%0mhv+6y~y>+q$)xL1X|c{p4pkuQ?TWE6Nk+ z-nGTX-cWJ8KZmz?B;lSkp8B%}*@(ls4CP)&ybfojH-0z9N`uXRt>C*G{F35_ughZd zBiBK@g}iz7{As~wk4}tacmy*rg?hYj3jz1Z(pnju?NUeU1N5*24Dw`zM~4;0%X)o$ zzKdcaNk&LfAVxG6J1B%{?0R>oQq@6P8umL_kk>9c-f%KGlZ}2`iITrJD($UBM+;1F0G29Bs?rabR_$H#ppwb z*yB9lc0PbcswETu7U#1z%@@9$=>39m=}q+GS}?yT;F@QHwo6DFRuyjK3)4*pmjN*; zsmJ5RIvC^~;3#hwQ`BsCJ`aSW+1}n3{JgvUF5~4VQ>jX)0d*AGH;QA9UB=vC_C>fV z=C}9Q-&>OgT-!{=ldxRe0ZrUqMr~{k%LNbV$e8wkf7v5j zYRl_sz0)={p+)P(OjU(pLAwDu;sa~ZUfqn{oIWAjV9~t>i+ZeZ;5b!3iOifJ50C4Ob zCB$aaRyjHY9%#RCn4zB3t&YJyAM8r?srWN`F?j5yXiJv*+aj?uY5N~t03^z~(g+NB zHXMl~>iYDG)vZQCik`lSCFT&UpbqmRF7Xu`KDJ*zkD{g=O%|1ZP(`0b-9mjaP>|1_ zlKPz<%hCObPX=TCwagx?EVtZzuDN7%p}ef2ns!}L#~j&MLX|IWfj0C@4Pw#JjbGSe zH>RtnrldMD&%o2{LpjghPe=1(kOJF^9Y=TjO#VK%b_5uhR@?1fEIkj<2?k6V7Z>Up zZY4)4!(S^(+eZaC8gTg;u=zyHVLR7%77xT6;OJa&7ilbHLDrho)PH)A8U>=$rbLC~ zDtf$82=l&t8mUytWufuw!kRiqFB%caUzkKk zRj%3gpNJvBs_=2k2BE&fHv=@f1EB>jM65V4vcjFo1*{l1$aY{FVbChhL}*Zvs~PqW zEf`Q=UB5=zDWg+bwK$;O$xT}H4_G$~KAs(Y7t9uEqz7;l#hXI>lWG6-xIKWOLXp!W zV=&GNc78M?N98^Fn&A$!^wr_uXaFMS!51X4Njod-je97cpm)Kv)q@nyxiku`7&$OYaS-oibtj+Tk#+^o)cpDrt7AB3tSwozq#K*qxxgR>CdRe+Y3&q`q!knruw+fx zZt^LI4=YhY;#vZ2u{!0G8sbLa^NceNH|-aCElsYD+&DK;UT6X9_u%ILX2~UZpocZ zdpk*=DK8-j!{StX0?lDBJ`AgGPach*5fNG{OamvzBXXa;Rl)we<*rs*f>LkBZOiJ6)ejLq+fli@RR;-dOQn8CoTdBGqMmhs_07plfHL(YE5uHis?w z=8j9ZGj>$+trRzv()TZMmC1xsB?AY%VnPJ*+??WCP0Ygl2W7v49tCU|tA&Pa5wJB! zqmqw#5&B5A1qI@LkVT^m+3Qh!b&L7zPCQi2HC+~%E&qR3c@?KmibOY4vca^;vqqTl>_i)wk^ym59C* zc{YJAQMZcXt)&-G&m|Pzf83G~9`*G#Dn(8ll_bzGgd5P}{rMT$U1%<=Tp-~yNzO3F zP>bfupS99x9_#p#PzM;wwIOV_Rmf1Bta5Xx(aaYj(7=Uu=>pnYw6n?<@`}4SOlB5s zqFoF?Y*B^KIXEJ8tGnZp+B~OF$iua>te{O}3_DIh_Qo6ycmdeayrM_e!C2jH5Prz<;2SDKDDI%o}C5-m$T#8lta6tcz`Oc?4yI;63b z@D!Il<0eKX_HB(x3ZBs&cz3mS-SD3rhQn;2xPB?mZQt#+cbcP@>##AhvSuh@!or4? z2L%|lw-x5+Syk3b248jqA@kf!k#TRmn|5Yh*yKQV@ZYgwqD9| zzb2hM4KeUngw|6;U{S9nAr7omStwd`wM8-ctY~yQm=?41h7=f3+LAEgdsfz7){Oe1hm~{p%EGoGj6J2Hg)*K&wX1F~gwG;2K1N%{oTQ%V~y#LeFQ;dSN1~qV5iYyg>yx#u1 zH&uwW9J?p;rMvd6>=DdXg_Zv_iz-9l;l=p)H8=7}sdyAykWWG)94s#x$#sIU=u zy?L&#(`kIo=dGk%!}-{%9El^7K#ol=qVB38)&Pgx{W=JXy(uHfdAwi1_TmXOWk(-n z;-`Vk+goEPJzBUIPRgnkGiOiAgGOU*z)5=1O#Vymu)Qt8S)ax@Hz$WWp}D2@Hyj75 zqCx_pVr;Bj8vA79s-iBVwpjHcC&kD6hx=!<$8ynPG2`&?Fe~nzfIM0Gu@-mqP`$?j zCizthGD_|6lV1i-#;b}r;qS_}#+5u8*p2eB8Odym>GaqWg&F6uN3maW>GtsX7%>3s7@I|7ydCM#H=?Nd^wr3`_@3A4>iszM|B zF(w{=9UZWTAN-TqHjdl@zt3*z{jb@4_V-rihxhkzuboe>{k`AaXKW|Nf3Xq~5(ds6 zM8(9}E!Ddl;AF^xfU<=dFt}I*s>7|X0v#RG>2x0A0|gn49D3&l$z@Dw*u%D=F0ACjpkbiOLwo4i|xr!K$ODSH3i zO^~b=$v&1)hJs=jMWvulVr_;Z5#x2MT|5^h&632%I%8@W|G}vpo^o58>2j0x*HH{bp z=A%0|`RYZKYAtUu%3Kbt4}b$q9*gb$`HHAo1+slbd8USz88S?UaO5VFyo8?+PmrP@ zKh)8!A^7oGWt1&2nnqw*;@gA8}g~%D# zqi&UfzzCl!Ia+2IbhE-e9cmNQ2(4YLn39boC8($*%L%y#R_oSb{O6m4Kz|sUS^3B| zHY$NwM$`ml=1fnDocXZ`ku6?gyW{x=89!^7`G21pAf(X@A4;vDY5c__CujL^Gyl?dJF`x$2R_RH^>vW{0fzrw|+7{SoU@Xr@BiL)ZlcJ~EtMJ8#O#xUz>+YeT6avrMdhEr{4IptRY z^wpTq3f9(6<57Y`jR*KkkhEUn?D8--;vJ})Am~_4VNK6pL5jkCa&(-B^e_84%ixPA z*c@z3q53ydDapz!mj2B8z?1=5hX65dASBH_CF;UzM4ITKU1+y>cQ({Q9!2Sy3;rTN|{)-n4J z2PR4F23ry-^xfUvOZv`BhQfc)?T<*L_h3a}zJ-vGBB`6>Wv$ynS;V+({c?uH$GbUF ztn4deG9MLH`k^aWP?r8u$?&vX=&E2w=UXHfWSzL`4YU9P6sh89T~1AyokFuYNp96= zr2|oynJ^`c`#NjcB`jGUGFsgLSt-gD*aA$l5Nr*mMLuqlK0_kQ1Y@wq)EFU@q)W8@$S6VmA#}~ z!E5w8c3C_bH+smmc<@k`lGD9wG7;ZLvhXi<4>H6<7H z=KV2lIbwY7b6aH;sC^GkeUigPdU+-u9TdzQqhhS z$&BEE3vDIDszFj+Xh+_Ml~SQHG(=V{A6^OHJORWY3Z^zjN<>t=dD7RFd9mI49}*6#d2wP_4k>N|K1+kdYco`=M7zL zZ7tx=XRiS*U$B3fFRhL5e%VjATQE=Gztc|SehLZ4^$zF`W9(;DTA<$UqK$gRJ)q9h zjlqUsq4&S5h){pZYD3u->Nu)p3mcDH`|N74@9MCvi*7dyA{m%ESKFtX*ZdTho5`G;75-3trN9rt%M2D-^rTX+zvSW8l@+;s;uLo(f6!bTz-fLKkD_O`*DJ+xZ`$m6(~i3>if&RPNTWX zM4BD{R5?eYHfR^Ub+h}H4=96XLqP)2qET) zU7VIIn~Jk=Td%7lFT40Aj978tA-Qn~2s-U{gQ5kq?q_9ocXoGu(QNUtF!Z%Lo#%2) z4>DedMuJk+AzjN+ORekssglWE`V5hEI*2+ z8to*{ztQ1J#JW}(DC$_>7$l(cj0edV27P^AnM|~B78gtLl@ZGBX)`b=)2#gKesR1| zqu&Q0BY;lQX*K^BTNELlzj|J#+u2rTp|6f1U(Ckd|FGsT#j>{Wdii5i80eYe8#{mc z1B)JtbEx4l%bogvkhx%JLaJ|3bEZ2jPOb;^ul?TaMEZKCATBO$X14Sgjx~{T?VHw} z9VoN4K&zOGhvtlk&uMY`H{3Es%=Bk$83BnZ-hkGjhN2S{s(*(nVPfExGUK$8oVdi= z4{(k91;x;aDN_jdS|Cf}zLfs3u<{2yF9of3_j!rkv`qS^b~_pAIJi!mHe>XVVXZor zXLAX#Vno2*r~^<&X1g;51;y9fySZ;ad@K>%->!|vlDa^OUJR>_lGzW@Fp3v z{4bj1vp}hh4f*R`1RU-6hLakwcbc7>i=E;JC*`N2q9UI^P}HBs`*`eD`=`+y`t?iA zWFqYz&@&0ksAPlc(NU6)-#lg&=;t4LJiZGRupN_))9*&^E5d=$bR{r!1=Gj(knRYc zVm*V!u_T)Nu46LS>cv}X+~=0+^zx0xXbdMNF5bxP^yQYP)Pva;^(?3het zt=Abl2qFKi*4qS%6p6>hS)!*G*B=vujBOi^IdM3d>i%>UJC@8;zJMG%cN`I3$zsqS z!dgZC-;=lhC3R5nhXQ(_Vt!VYZhnvsLjv^h-K(8Z?RgBChllbI+9X#=7B9{6F&Xafykphnc_6*W0nIk8HUC7Nt^kby3fAy-+4O z;r39qQd6Z+TDIHE6G&T{FsavUUUqUHLY#{5YC0Q}y#0rh6Zp9M(~hHncQI!fBQ<$| z=*yHK+e@lkI;TdZDxh!IZUu6nb_c>ShZZVYEfzPY1V7gRtsfaF>Dhy}|DPKB{W2il z#rbIZ1GunJVPRheLH2x%H2{_59qCuH;2Dj!jhUU+?cbXY?kf2Z!$H)ouDUTEg>ehR z#Cr%Pswzxzej%$>gNhxz*k(DqM){y!H5GIIoK#Y9N%)$Xwz3Bfq`eIAeQoR3#d8=~ zYG~p|_B`qAzl7(-q7ezT^TqF(u;{N`z&mxJ@G1EDJ$Cv(&sW>MN4^XGVb|}mt(-8? zdLJS>=X0VB)=Q!>{8h>ZyomNmU(Byf5m^!%71pSUH1@*#uBlj_yv@!W;4SE(?8fYx zIe&Gy-Je86$i|NtvEu@J`*!!KtlgpLPC?HXz`75x3}TA5?rTKe?5Dn6o&cjY!(s8a zM`~w!1*i*wiPbelDfJ+AN)>)yZOcAy-)=m0) zCTjko38A*pGsLUPd9sfTSGP1?XCUCT@iCU^PZCIf zp*Yc>U`!oXJAi5H>E#p%g7oBKW&L9G30$z1hF|SKSQ?Pv1(^9KP3oV;t3V2oMX@XK z@vv5lCDJDu`qDV62(=hU`GtktxNcfdm`J611Ufd9gkZys3QS{!qFo%!i|n_R4z|%s zy@`_5toR*Y?lk-fQy@D^z_J|oVIQzAfL+4trMKc0mj zL9B1S^wQ&IUmrj zN8P&r|^PN3Uzk`p!T&k=s!&lEB-~-cL$o73pSco!5s`E{DMg@6S#%)>KJI z+~B^M7R7u7Jg)f?6fIpD3ABeF3JS_4-;iT>6m+!A-c4a)BVf=dvjm*n1}?h+b*_1% z%N78Y+WMx-Qw?rN|%PUfx*E`0oc4<#s|-zHswYqfhs#-U?hQ zsEcmzYa~I-^)?7~bea$7uRV5_k+^z{DSA;Jf&VSfEI>FuQdxEl!qCyVzWUgXr?8N* z0aAB87?pBW3QbIIHETt_Y6O$tHP@;(pr{BqpB0-3N|B7mx4l($)^KlbQ zGd?53%qQr(=juHt{sE+Fmcmts}5pU9Rx`QxyajXsbMCVM*mb4 za?erVpE5Nz2A<5SPan|g?_QM}b44P-U%h1V#i^o*B+PkneloPSwgOMZ-XMZ^rFP>< zek$9)2tYtAeVl5VKERB-qh;o4McaIL|C9BxG0Vb1ImA%&MSFtL@&0 z{HK;oA_yMO`RwW1T%|mYHk2{B9{7E_KVDY9%OuHqIOPFZBk%WIKFI$trA^1RiIGu2 znh)dSdGn^5)eYWIGyxdwY`y8@Sn`hrX3|2{^A*KdMbpVQhlewsBSBKq40I^sX0i*) zX)47NTl`bUwk^;pQc}__a^`~4%Py^U)pHV&pa!#q;5Bp;jS>ph>{jZxweE$Sq|YP8z#Zwp0_r*Y8zh=ezv&iNC8LnNQdD&{nq=u_Qs zJ$P!9lWH)u!+h3eeL#0`lwMo9plWp@u*@=F3hv)5nVinRcOy zG9?K=4-b!9r@WlRX&Dd%nePu}BmETKuhS=U*)8}!vfanmV3VDZ0lz5hof>W9z>C&bjyg4ENsaU6^yO zXN-A&zUDR*iLF)pU_Jn>rlQIO8=&)(^L@2M;V;+p^u8%?NK0OhvQH)8*s+Z7Nsbp&yZ@w`rzi{x~u&?qa?~ zq093Quy+R+LW@iF`}&cT<(-Nf>~VuD__UANn+{;V*%=v2#Wr4I&eF$VAfEY6FVbq_ zPp>k(p?zrciHzeShSuDK_S6`CSeTeXc7NCV#7S#f4+{R9bnTZo{~iuRp>Gh(mT!ys zLa7n}qqv4a;)%2(fS}OP(PzNSf3-U7eagAJ>h#ceKHcQv>+L zo~j9K4t(J-LpT^f+(i|MVGnX&J2b$tNjBCu`r`*>e!Y2w5~vd1#E zVEPubmA`9x7)d!F>kxDq{;RTA<67nadl;<#A>LO*o%kGPVBj)ezAUbQ)ip0v>%RPE zn|^CG9&L4Cp|br-^tjy%T(*x!CMRXaz{h}sgEj2_QNxSZqrY-Hug4gAsvbA2x&0pd zU@6Uin{(c_l{^4(oY}+=5A9QKz|z>IZQZkr1a1DOwpxB*T8QorlbEIuba0v_9^ zYZLp9r7AnfF|kHEi7Ix7-N9r(l?*N`DN7QIy5G#$Z_l5A$dHuSuBWg7Hxh;qIF58a z&pZO>5R0Do&QH^;F9Aen8!gkO4d}4wyg<_6Ydn(&@S?0pgxJ{d3M_h^N6!4;aCN0H zf=kQ40b|r)xp=bBDEDt-AB?8~H6I|-`{y8>m9@TRYqePI6P7PdstsJ?r*n)#!hX61 zLIyCa009zScMv^$f%q>JmafMF%1Gc0czQ$K>e$HnGpTL8)g5H6B5hCzpcxOxJ~ab7 zmsB-I5=yE~TuWChU%cO9c=$G&@-S7$fdtiIW08qj2O=YIxA=3*Um>;E_ZN<7!9CZG z`MK&|{GdLtGvlpIp+L}&NmD}@OF*V1;VuDi4r-~=%Brf)K`_XE+I5DzgEB#|sHrAE zOpa}c4KX!a>EQ&zQ2=H*4XK}Xla}YhF(xJ^qz?quYLDGTNHQWMEK2YveZcHkrlyPA ze1-yuGNDq%rQz{Yw1h|8-(NjI{6OVwa&i*7d#+6UMc?<`V{Gk0hp-#C8HI+Hq%vUY zw4_WtmQ`HeFV*WBKFpogto<(9VESc#p2MH$`$cLvT+*n-Bf?BF@V?%+KHf;};dp^o z!BYYP6p~+M_)u#AH}#G0oXvL2BnC8isERS&sDglSgNlKJfs)hta4I_i9UTb&gVlF_ zE-W+x_|p~v>2y8g?Z;-L1x1c$LUfl-DylTZUk784V5=Knf*kV}Y<{^=?u zZMjl&elKTp+0miYARGut6Gg7^BaSXGh9+YTfV$iEJ1h|5S-tnO08;{wfB>N=pwpN; zlgE0c*7wb`2@XAW$zrMU_c4c=bf8w!XzB8)|5$I`{4vDle2f0a;c#?1hZ#zn_eDS6rv`73#d>;a3f6D}^?{pP%d$8J;5abFsQ08l=_UffE}Ax4Rf;4sUDheQfg z3wvQnCq_nC2^@+PJU!d{!ZABW>*os1SYXI7WUz2TIesyJoG<_La}f=C4g~c!Rj5_3 zx4URtTO%LghsREuLbBh!L~hAYQS5r1I=7v<3S_kvs+4e5sQUr0y&O^l%6Ll!MvFZV zs4BFYay~tq^dOVGJes<*P00VuFJaLV17(4H~fM5uNsho$!N%=iYYHj7ZvJcmW0dvYAI*9 zI~)uZEaY?th)F-~?l$f8GOpY5*yAROZtY!N3Iew9;S9`tkYG4sj9=_AG-AJ&1eFwl z?+7ucA;wmySFBc9we$s%p8H(*q!_ZOI3$}K`o0@G>J5jeU9~@ka>mvf1I+lD0Ar{| zI*A(|)1QwsW~Tw}X$1!8^W#o88|NWfgm)3LVTpfF&SaG5yUer4@!Z?XeYM`r;rkn` zMygV_y-RsyuoA~wJ@g+9<0+}%>PPsXNDP@#ySg72ryDO*%)0ICF6!P5e^QQc^8;z+ zv_gsInU_E0-+2G1iXHj=QTgjk$MVGmDvL2{ebHSHK(rhMEz#8PQ5cwT-cAUf*>fLa z+E=G{CL0WS*zDN8?*e-Xot&>ur~B1*A0$m2>DG_3SW&@bsd+(COv=T&u}q{&vZIP>rA1Ow!{|NinQxqhR)R?$|_^52>)9%r=oeG1Fqi z-q_sv@VQ4M?2+Gzdz&ofx9BvNA(Y%fo6^LKP;5HEGX~(Y{9C?~;(mU6Bw&9Q<7w)w zrnc0^VHQgw;Cgwv1HfvRB%;YsabfCMzbgz3@b>4MYLN=(_k=@DP8Z4+pYEsbPM0j~ zfGt)~w*cGX(bc;Rz>R#GMf0=cVe-yd=m zgBsi{^IRj%q~FHu+P1CfoAFy85%cHsxKJu-!LXuSMfxGFJS;lOBVfL-;@+;(>FvZb z++<3RC5jf zx5?B=Z;TN`3H$pcf+Bh!m2izC4e_L${1yM!Ailajw7Aiuo~YrbleER18D$yE#lh1q8!~@$n)RT#yeLxsNkc>HlG<7H0r2 zO4lf~{@2j5d*R{)ONZ8PU&~@Sslc%or|)o8Y>OHpG7}LSn++5$h+5~^nzk%O@5kbAG+R97wW!Z86UKYjj)51K<$qzcw>7u z2TpJniyz#24=3hU`FpoL`!{r+lXU~6_M2ND!yk#na+9P}59VpT@)5NxmXy$5;@val zfz@N+ohq3YYz)1eBTKPO+j(MZ!fzQq?}`13x*1iM^h-$v%5Sc-k7kkAJH0&CgEL>k z2^}*b#L)N0?%KT^Ba5!E<2yh@9j+5E8&Ke=UT)_WA9_z`f3;l?M@L*D0()MWH%sfB zg!QrH%$Lbae}W~d$JfN)fR}@i?6(UcW z&Hqc5Wi@S)dOtmS)}+B<_D(H@0T)t zxoCo(e(>q_uh4$WUv&Vf%{{<2Ly>-is()Hb=Qc+*!sFhozJsUGY#A!N!w37Jb=a)& z`b)yWZfdMVRI_J9_Dsj8UD~B%rRl~A_sSUBlzF0L6g13o*EPP}y)GK9a+CImpGY$M z(lL}g?y0PbQhGJL()8awsAv=8GB~ih@?U)YI(e2I&YuvFCiGWbEYF)>ZjTc`zZbK_ zzrvD=d~UuNP+s3MYIGtj9(-kcw?s1ZCd-%knOI}jWlVm)^RZs`w9eIh!6Z03>BfO{ zv)L3-8y2=W@i^_X>YmMQ&HIBj@rDMf7NS<|-43mB`3F&BPi%45wU$EUSfO=aJ5ERm zqA0NIjyJ)K#Qkt>oAf%w!DM}1<8SE++0E$NI)eNmIRA8O7DSW^xxn zX(^7mu46VQiUb3@q=d~L z&oTEpX**9Z6Xaat-uaXMX^(56QbGj^w|tw-I^KWt;{D0!m1Hg_ZKAOXcoU6bq^SpDR2Kr+pDE2Xh~MmNFMk{$4GF#rx%d# zIPy2tH@NT<=xWq$L-(1pe^VaA=v7BBVH&!`-X&DZUn&Ut72+@Otj#06>Ta_l@Njdk z?YT%Zh)`&uHr$hG#(gr|h9z8C`x5rqG4gg(C+(wast9U`WLxY*$NoJdhu?up?&wFU zw|1oXubT?m_o)Z0;XTqb4*O`MssMe&$9vO)QD-heI_fWPp?)iCSs6^or z2=VEkDfk!4e1A7%(vQ*3y)dzL=T&pF`89aA2r3LeP3pA zqjc?}hfZHdd8X#3mOuUqzmt7hfW`HoM%VstB4xH*YV7s@uy`|zbPQ91)(x|YlNHsB z++ldH{8_qh^nNV67}U8r#=|(&gJsyaPfjm7TF3}ag(1)!s1EtGq#|lYtJE;l?$73Y zJ{Yq4!+%u<{5h@wjL|@|f#}2C`b*`$L6{54S^$TXCFThfT>w1=xt>SMWW7&nKuWp{OyF7X5JwJ-y+5iukBHqJdTyX&I@imKR% z%)Y(zZ~LX+1QvKvch8Gt{3a^_LOas556z0Vs7+w>c_<2Gs9ejLC{ z7n}?_NFHQVkgB(zUk^N-)bs)G#c@^aU-$=z*owV>(qer>Db}Xhd%?8!@%k|~8{zmZ zu*9Doga#f<2c8B+d4Wnzj3{c^uCpKq(vR4n#KSU16@hSN!-uN4236?e^%1Dl(aj%!vrjZz}+7IQ%#&Yyl#wW zmUAv~ zFEKz%(&Q+A&!!y+a3M8xuYMN2VPl^*yT@iFCVrb#$>uHAMb!PJCJD3J>*GchQRI-z zy!rB6Bh?!t{ZXXMiGsx11r#?c>bE7fi>@4r7b43_Kw*nrl)KC&fwU}zwqF`1&I z>Et4kf4X;zwMw(v(8@|`9%TSIV~_g^Sz3Nw8CG)rdVK3A!dOrn91&LeN{RQso9UB5 zOyw-;tC^6zyu4&8TI-cR@Op0SR`p!Hn1R>Wz&%U-6%Hyj^FkBw%gU)0Qu#WAhNiD? zJaqd17(3J@@?B|i%Gs1WT0iNwaA9?T9K}trZ}V>7oi5LPy7qrDZ?%h777wYKCkXy};3wjB?KBl*# zcC@A|QR<3%EKJF$2QA7BSFwk7ZOuV2Q%0oEW2@_!@t`#t+qKgy-NLJS)@L6 zfTq#QH9W+31ej~pm{#bQsQfX0#k9ELn$m*7#_(+l6e@4*E(iRfgMRTuAukIdX)(`d zQey0e5|kcj>dliqr*^=xA_y=22i=Nxt#k=AZL$B1nQs=@x$EgG8Bmrb3-|NCVfPeQ zj*%eOg^R53?A62jYG|<&hDQfZR+GLwe?7^K@Mye^5 z;}dR@;EdBYCRG%SRB1AMoZt-J#*=E}dKmu#Hiw_!j?Wj=RH&;m5bxJKZxsz>Wy(K) zmH;>_oktX`l@1U~MOFkINxce(&r&Q!u6rdM^0ITaYn?!15W9yWCs{m@5b+e%csA)$ zkxhdShLZ8YdZ6qWd#o=OKmBFjE*ULQG0n^YwS0dn%@$h8G}+0#gp!35PE!cC03r z8&)%`wDJ6H$C=JdxwZj%5myf~qG*hgW0M)UXD^2s^(Gv}504Rvp6&@m9wLB~5*rB? z7Hh{#zTtAbP(EnT%0)?o8Ig=635omMyw;`OhEg!089pj0|D%QhhD~aahKzY(Jd=-b zEF&PxuUt#yTdF~IQb?KjBg4q**jkE_z}Pz;8@r(xn)pI6qwghbe08KJ*-SW6@)Lc1 zOE1Nhqq9u5G#Az#&hCka!k=m}zK<{sDHGEo1{4*1JZw`XgiolD(tacdoQjwn&qv)^ zF|F;iju`Aq*EtjKFnp$DmOy z(J8dX<`Z!HgeCNoaand_7g!+F?HE`AtV@#3VM@>AD@aff*ecpGF#?E^I?2;Ns~lhV+r~61|dI7&KL7l+>}V;Mi3kTuemB9>}f) z$KK&S<2lgZiJqW>a0Ald^al(whU}zl-SpJK#(ijC9g3!L=_NPpYA^^}5cj|97F?44 z_^K893P@v4kF1?H!k`umerr8#JLKzRK>z-cQycwF06O|{QqOqX(%LY zK>5&*nOvje1;pu*pL%I~q~mYF+ax?##c;Yv;p z-HLT<6g{*g2mXLlJ&;p9H(Fd$!2>499Z(?HWDJ#A(#eYV89CV%H1)eLb!g}Fd0;xz6g{PqDU z8BOm!%5YQ_ZC4sbY~c9w3UoaGQ_!s4N!X8H(!&z%uhX2o!^@}5E$-wjay}i$4c_eH z^RNvL>B1kh)v}bQHIlsc^0flVIA3mEc6nE%v?m!I96&<71Y(&sUhbJG7MmJ1x`=Kq z0@xoM;68ftDUjqvuL8F{W%nm##*B2+`pE`(_Ib$NGbp3Z2+UC*$q|Nm+cNAJHgx{y z#DdIO@~H$%I~iPaR!mU@iQMSC(){$dtpgepypWApL#WhTx}h$iSLVngD-fye-#I>p zSrh!hu@<|xD~5Uy&$W)eyP7FWSYo#`kKrt8*$oPOM~DOqMiCp1JsPtbxuH=D*vDK& z_^N7t6j)G9E|;0u5$O(*ZYQozP3D_cUV3>UJN%XAPnhB@;fT8x{2MD$q$ha#YF;!? zg1sWwDU>r6#i=yb9Rd4bYLNna!BND>3X#dzA(WwzSbAfmNN>zz3Ry#UveFZ0AsVPsW}Zr&-+qlV> zE^J+f&3|EYq<=u%kFE(28YAKF`s(3%#_9V=JrKbeN?@3|rnw(^B zh$*N}1QIqS9X8_T$mImnebE!^fsb~FC%nrevX#xNdD%Yw3UDlNN`6M-9fnnM5n=b( zfps7&l|&x(BcG9p*hBJVg~rXj#AfH#s3ysdnz!kdb?wN8K7l+ppqycf&!6+HmVIF^ zG8w5wxui$KeXi(|0z0lN`#cx1>h4=c|z_JQw4(oj{ zo2j(i01kZTDe~wi^i0aGMD<)WLN%tVQA~oHs+M{=*RQrJEM53xY2I^}hPw-d4(tv& z`6)oeAsci4QY-IciS~}xYl@2^Vpz4dd%Q+bIsyUW3C^q3-`@zYc(H^1t??p0AK1yJ z*5d5KEUh^Cl9&ZP3+IT-AMh#Saru7hLZQ}XEe%q~@>N=s!_vGQqSeTixqC12PLRm$ z)VNYDB%~yJ%~1kX)jP~SqL>40PF!p1hcUdOHCS$t-S{ij+``o+TcvDozsmxJ=bT?J zd9X%0AnvZ|yx4p#%-@cG&9@*3%yPd9qI)FiEBfBF!z@9iQotmo5|==Dei5@p@EzkP z0u{q~2Ur7GXd{D65xCVd4(0pre|7uUWV&83weJzJDfSSFbBp0W6wkgu)c2MvrSH;J_!m|=>qPR z=3iECPgkh&c6H&C1y zuY`!-*2(^*RTCgKIvaX6iFE)I)#lTESD&(q^qCxT7~<#&1QUOHK~k zR+SRCYC^NIWDQgK1_t|JV=x;~2l%KCC{93Nalz7=z9w@~kU{gkBQ-ND%Vy>0vXu{% z#+1K@7np+5zj4$bIc(Qi+09_;1Qa=~WKrsh=?Ip;Ga&dOAFB0vT>6_5O9GwBDhij# zsW6>T@%;0J{?hN`X9b4f=?P`l5rkT5j-4l!X@zWyd>KnLO9Q`xsjtctwiZQ`fe|=% zBwCbNw84bo_6gt^k+W7SJ|m9JIpfVP@ctyJzaXVgB}IP8mq!7tOp(vj(SzO9#^}#? z3)rga6Z+(3f|adzWojW^krB9DKg0+j;k`T)KcDmAN^x1$H~m~vF6t*ZkD30d@Y8q z{7{eIpKjU{NaJ?N^K$(5YvDmViTXg5-=QdQQiS0;+754G{w`pVS)tKQ=1vYU2zQG5kJTeO|h180Sl6VVvx&h$yVYSkTG+Y;612$9JJ!nydPq(A&DEhPvav^#C7~w+$fS=K^j}QTaJX~R}5o6qS=M}Hc1LF zk7etTJy1Yq5K{{n@BES8WGs?3RSfL!k(zQ#5c})ll;{prKAu7^_P@n+k+b@!3?(+7 zX1alZ;b%`^eOkF?5r`I%8Ml@gpD=%Ihkf0QhiS zE;FdcT`_8(Qm;J--sMnC|4B5O7O=%ewVGo2S4ox7+dl0cFd2KEsYO|mIpd@4;cu6} zcd^N$a&0xp40A`D&ejSvFkGN`9^4ST``;HOOkpkv%*5hoF z>z*G(hj96~mvD6t#pq_UZOCet`RC{r@=Xr)dko!p6>@8&FD@;8P`zY~A9vYo6&4Q_ zkz9OyNI8?3K^%1VV1|8gZ5fv=aV(KAg}96))cF=@G@v1I#S=SzksIrVjon4eqGr3g zUzVQyNY!ayT|1DG7(##USDxifLLIT}2O8hU&g>HvL-ogQz5IWK{x)A1YyYYDWxKu(luZ7Qb~$p)g`i2F$#X6Q}$-(WU()f!&r#Y}m~ zjI+j?pWQ+(v5}ieXl)_q7DXNF-W4K)ky;8?`X6O;4EGFF-@MMmDzIMGm<8gyu_M=1 z;q+(G*dV@TYde;c(ZS;L=V@gk>@W~Sg!>{(Dh$*qQ8}lCFm@@P4U0WSwlEM!rpFWr zizrhs)+a-Te>3lwX6~&5&*_)>&N0Y+d-PT;!*LF3iOrd^P|ghrdZv$rT0e6}(Q6SNhCn2|K%;>8lc_%^s14bYW9{Am8?iDdb-QUhe(cj#0SqRXvIqij z_0grt&e~dz=LnNkY>O+vz30^Ia$&G$N+I7KQ5WZzyibtc6_QbTdZLXC-18z&!k+O?Oj+#GW6 z9O$_oZdp4&OQH*C)hqgYD`xNr1fTu8zgA+XryOra_?$}ay=~k&;UHFJ)<3unXy4r6 zO1c99HDn{@Tbese=tv&tHE74@TouegqFML1tH*eNU0 zJxY0S)xSJhCrE@U$%oM-I@rxHZtraQ`N~A&9` z&wt5YBS7@YjP%ngcLN{B^h31NK}9~2?CDPlX?Dj{XC=~&BD|bbL1cOnGIk&Nk06&% z=!`JTSp(lIg3+gnyul_g1Ut7T;-^t1vq+Ukt#j@55^% zr@~v(##C{6w7p7{@G|ufACm6j2(NKAZpn)wb0OtOdHfTn{*6d>==g#ASP_r)>x((% z4|KHeknHgbe#JnLiFJTR$Cv^URC zwxy(KDeI>a!Y-r%#oWLGG06hpJp)wNKkbgFgSbf5M2GmnRvD81NA zm6|~z)n8#3`ph}&85!ULX(N#a+y!&O!@~jj!N7+Yi-LjzKn=z*jw9kQn$H!DF2;b{ zavBXs*K|Ky0?Y(4Apa^p7)_$tuyt!NodoLtnzg_dpX~G3J+s;lHEI5*cf&-}KO&(D z05+COqN;xp5BqCLLbI7Aa2%Juo|rpjw|6fWK}7|6U7kR93^%1@DnN+>7&mA0I_%y| z3-|cGJy(1{yYBYei=;%_aR7e|aNg8ZR9tqOS<0y&5Yh*NML4|-Ka>x;+FG|s`Fv|j zAkK_e+y&yX6GJ4ce$Yb3(OofvRP(M@X!buQLeI{B#~vdVO_v;vi)s3!Oz95#3Cv6J zZXvhG_OAJA?&W+G#nJ~SvY1x1Q^e0tXCfZW6n$`QL3!JVm*DBfkDMy`J5Uz-`&} z@LEy-ufi8JSh^78*Ct6!H3~EiYNf6E%$TN`=V=~9%d(jqwHiHQS~-9K1~^h2ZyLaN zDNYIf1{$;JqtY1g3{g?TY8h`u8NJg@o(GG=3K428H{sZeSl6xj`E=w&evK+Dg4Y#w(DWhxO75r7q%RN)oS zO9c>=-Swm%K4CMcW$`*d=-B{@n>1!!##HjCvsG*E#}9xzCgO7hyvPCk@9b~K#gZPj zlHnLSe{ugZ>-bn?|4zP?w-8~}xEgkx?k?v;$E43C zQIU=eV!i}QL8GQ7C(Co#`<(lWKq(1YUv@kml?ao$c&uvo1_8TI<~t-btUk}zLl%P3 zcnF|{ic9PM58BvA4PM=`zP&eTMpxRj~vZdx3u?CM;)lPrK@< z%M_rb0r6MEo_UDHixqiX$9jrgk0^~Inl2#xu4!baP?-G|F!K!CE^7u5=Ddh zF7~e*x{#-{5)Z`c70{L5ZnIM})ns@1dW0g*8)#~-q@-kz0ZE>3R)p0UyF%hv1}=vmYN_867$pZ~ReVCby=w**-6V4|S-;DzzUH$OKTYi=($FE6UM zmp^(2cCN0jrmnV!92{HeWV3*FZ|7*XFq6j)#gFVyp2e-_uzdkA9|?JE0ot5GHg(Q; z*|(VVr@9%oss%{q$w-_DW*_@@n~B@$4`Z+an8$wDovw1&{d9>7clC+0;pPWCU3_VG`Gd!q20IrHA|3-Qqpgy`q=g>{X!c zv%)-0vz3*qirs3}VHhS!Mi2i~*o_Y7pC?xaqXcO&>~7PFkX&6#&s`oWb$AT&16K@+ zvyr%S9~o*pog(T&twBg*(}hQGZYBg@BvG{ZL0`@l;eKKlf~^Mbyw zk3Ao67d%_unEU-e#~)GB!QtURJ@C)*1P>QmTP=3_09Gtv3-w78~GQ8Ee#AS?lr zf3w~sO7`b!tpVf^3X+M52|6NSwSxKnNP>M-%a*U#STf!A^(4=hziFVo$RJ>r(n|&M z!O(cVJ%-!_!8;vJeUX*T;I>(<>3Ns6Hdm}qhL~y8txf$sRjWeCMHCiB@Mt8i=tV3v z6zwds(TnVgCN39G;9@l@69=I`DFQ8H$y=)G>8uzvj-2GzNKthgrCCRK>H>0@OTFScGu{SxGQ!Hwp5JrMowTYhl zG4O$1UcHZnILKWulq90eB4(J+k5on`>^6j?Pu5J+JU-HjRJNL*7~0U2!^wrBvQp(k zEa`ZAGxMA#8rgb=fTGOXRW?7iIeShir4dPr4l0lLO8Qj}V)A~7T9%h6=U)W>>eO2X zTOiDf>V<;m;W&5zJTBR$A9Va_iB_}J?T*U8Km*&Cu=4d2uEdxMt!3A91{ z97_Zb_q~}v5Wr7eXYxcr1S0kRyekc63V`MQQk6FBT)t=!jBdL#dXExt+JiXfN-##* zfzy@L_i+aR@TrzDLdeo^omqn(L7vcq$PNLt8^C;cx#-zyvRYoLGqPGNhb914%jX(^ zjtBHC5xFEno{a!?4(zia&FA~`sKlSnyuPs(t6zx*I#u%i20)fNV8-H)Ac2~js%VDs zvxMlve-xH5i5DzLnCZ0H?ouL#lazv2}Mr)=^=$HU;J(`~5=357{bcOki$;d3L_sEP5v z_=CN9 z`uv9ZppuR*ZfG~YjIi!d_5DxrS0|B3SaQWj5?XronR6Ppd0Afw*Ms56n_LDa#jBT> zmmp&Ryv8}iBPIQ~+!2pQl&C?2LBaz&*#~y8iLo(=2S6aX(e2{}gaRPL-i_lJLnEUI zJ+j;5d9#stGGMt0`M&Z>mbfBV}q4B(b zlSn5P`a)Bpkw+fvY5TeJ?hTsH*ay7>J{dzMfE=r>Z2lFiEjt-b?uz28e4|zoDHTV@ z2u5licI!0ihgo7GB!-YYN#V8^*wC3?@s2__XS?=w`r=!HZ0M{xpy|lN19Wrxj}U&h zaPPpJ3nL%_shDR>0c`%%RA>z%F7xfxRX`6i0p|~4KVM7B^2ZoJWd+3yv?TtX@$KPa z%`;RxUS<|Jz;}OvCnN9%nv!pZ1FC~|m#5{>urL*Fwc(XI-(pqK8Gch1UhB_BO;v}d~m`cCM(hOgLZWc1;b#Vo?XZ_LybOV za4_X`-@hkMvRt*S|3MR2re--Fp%X{=T$ZZ#_VzkDI)E0y+WIV&NxS>$Po`O}&(f@} zD!suW+p#8Dy}18xYwEv1yO)DXZD|mHb~Vr~opKer3v^9Bl%fMiCpN0gZ;!0w8zMR( zfiaEuvl4~o=fOFK!+c6Jvia0^lY?SG!~TAK1WAz+ZlD3mlY~pcovGfDIvyw;Y>4LA zG#_y!FUo5X{uffzGJbxy{P@W4?zyc+=~Z%H6@_aF*+=UJP@?{YGLD!ks~_YsZH0jS3g%|}}&CgcOg zfpcfOW~1p$#6I3Oam)8*a(1Kbz&WCKmx1--57LR-GN@3DZFT|){V$|G9niFNmD@~D z>aU z@avotmeLaqtK3O_BFC6OS*yy{^qs?|H@dVj-eMSN266ac&szYDJP(09`ScwoGtbO>^q*Y?`?7NZ9R%pOBA)j6sl>FK% zD#>g2jTx7%)K(@cOV!kSFL9NO`E%l)Vu9rImyIb*I&_>X72)Kz7oN4~tQIQ$OkL0Q zIyNnguB&;c$Ee#C9QXvH_@e;*(rvwlwDk2U&Y5loo}C{`bSF5Fe?N3Aju$J`fk*(A znEw{Y&K#uZJ-glkn|2Tv?UM37kPeNGjL@2^H#ka^%$F_pf1U5_>;zOt{++<;eFqY| zPAfVlm%rU%7uN9q;&;E_H|-r9FBhR5}MRnnCX0>sW^yB<$o)CqUb(+-A@oxvu< zD}&t~NKuOaFdWLwI43E|(ZIK4Gx>KTWfo^QD)#bsr~J*jw2*Yn$o+8f&P0<8PZgvm zt)Y>#z74a+SO`ZVXazal87%&rxD@ij%JBKb&$DpP`avgo6<-N`KFz*V>qe-ijS+B1 zM+Atvl+WY|MJt+<5|=Sq8N^t$+Cs|;uf;k05y@~-j~))Srhj&cT%$@E;qX!VHPI=$ zYJU2b?)FksyTor2UwPQ`30^fK5p=IIVZ=I$w1=ffAx7_QGy3h29;ZuDH}y50YvGOW zMGjy~Hf_HiA`AiIp=~?Bym@QZunrAU!&msTqT&oNhi9bj$n1NGi$;UtF-2N~ zLqgtOZ>F)VxI4^e$)|=x%qgmKO@Scxa5`5X5QJau3=nczE&wlec6J8j(@SM4umz&> z-$*`rOV@?6yb65sxDKx8K{?=#{5{X9;Ype3KCDU+|9pt%Vjg~3wR7=#)TFT{^<+jC z+D0WN!?(JMz0x*-ywhuoNK0j@qM_XqOj90*v;L=x3ZHvu&GzFi+PClicLoGq41Ld( zN!CJz!R;TxPmG_f1QJkN`9zH5Oj9)nNMt?M-F63Z~D5sg*P` zz6VkB^f(Uh-58$BFE!P!Rn@8tcGFMZUVqv;pX?TULM=x^{)+@?Rqsw`&~i(euN5|L z@z=GR92+9`Yvs~mEbKPJEit5Gh%1NEM2^RBhN;sMRoGRTh7#I9Sdre9mv!uZkSCqY zNnRcXhBG*T&<9964{JK?nzVqvf2T`Tu*d|1xI}lS%cMe{oN(d({$Mlwaiqf4YE`Qu zseoj#|JyeH{uJ=g08ikEj(>dHeV!Pv`~XFc}R9Z zpTm2C^R;T8O{N-&mZFYo1JCtvyO%B=rMV$M0t}xrX%s476hz)kmltD>^ByzEaz)O| z8VtfltA9fGW1%q|pDV=tOQZ^Zq5&Kn9_Z<;XTv&%9nVra-YeN5s)m1BXf@G_AjG(Z zBduAi2=vSuFnNf11S(m#U(Je?>A5E$pvv5xt!iR3ZH1ghWvzp0;*_F&^{DFm*_BcH z-f|OUVOQ%xaDmCEEv*<2e)rPPDGb`FvM4Aa68ya8H!PK$N(lL{5yTnDH3wIUgc?iOG!EL5mJ0Kxn#*!=ul zyWsNi&#S##56{Q;w=hz%(56~L^YVK6o5WphwwTp&Dwk3K!{D7>Cd&ml0)FGm z)GwKpI6L(sggtM~UdHO-g2BIQ>~in){cJeh4T>;u&px9;m95N7yqb-PjdK3LH3?9m zQSiP#rm;9yV9ymqzrw-6S*lR4DgRaxXivt>-bO?Z6dNCo?}n8qq#QpzoNu{3Ol=&( z3QgnUST<=D(p?XV_7Mp`z1#%ByqtJjWNZSm&93BRpw0sW^@xc|og`DGya2<1z}~w*AgL$!^>zHfk~Ho= z7l5{=j-qwF)wfIK7mDa&1=EM2sp_!WfePMZ#iAkSD2f( zVd(+%dFc&ixi-t6id=~!j}f0#%2WZl>?gps44BIHWID_w0a<5fH-}ReoF}0%gjXA3 zsHD(-fFiu#Sy^czU8Q8(E~)s-lW!;z@gLG{H^Hlx+eXg+7Gb#aM&h(q3vk3@9LRVM zkF)eFRLblD#VYkO<;;m{7dM*^gVUT`U(4m<$&uN@r@zZ~n=^z+Yp&LItBnpo*%1)A z3Ap+G&1|xQP9v3-RvbIX&OMdyes|qBfAe(lTkoo{SyMAGFt9hs%VoJ#iUE|2^<-_oqIh@tJlNXDfT}UW(NqDseqJ8%S@^M~cJrQ? zfIWjsm5DmCxwe>T#h!_*xaV!DNw}I6C|rK7_@dxe)zD|n?(;UuUypRp>niM zd*Y85;Pv*!=k;#+RL|?YiQnZEa1gs#@&jxk_8S`;-M0L4Z#;GvM*Zo(t+rVG`sBk; zMRjn$A#lp$&2yYG8k5PLFm8Nxb%m+taWFDVVb%REm9M%oENVAXVp0^gXa$OAM9cE? z*Z=Bj+ufJfq(M?5R862Ld0NP{8&v%E_Qo+ccYS^RKO0+h|CC><1#LRQO+oALE~i7D zEuRO#Qo|)GI=IHM%}SPy?9+RicvvQn&GlH3jQ7JhE{k4=Cl_n&SiNM_uO7h!-uIg! zzpw5V>t1zrliHl5yymQ}c(+dx5x;=Vs~DL^@QdGrkmF*JOcG7E z;7;ZRccbl^>nfq$YQh&&Ctu%Bll^Y$bc^7=;8KNs{Safr>Qzm1l4_93v{>N2?`5bY zVxSyjiW4hf!yQ}u9rz-g21e)h_w`V?rp02z@xJ84g(bMl%dc6Zs>|zc>BQOlA$&Ln zm6R_v`4+ZB-T#EkQa)p_a<$%O4R!Efq$W(|@8*G2h${W!eYSwzR`=vFw#fP3&9fEI zHgOD)$G6cl0`78dASYI;n43NLmGOTE$f!%y)iDTt%J2RYb&|vVS=<-X@jl3&qZ|Yj z!xJSyy-G*6F7x&MZh3$|+w}IwY@iB1&YB#sohVhw_AVAt7S5KcRj}x_CznhUJ~|_y zmWJ_HqF4LF7$Bc6z;^-b>Q1S=Aw~9)0gaTpfsTgfm%`!aujs;owv-i% z2)@Y(Ar%{P|D8Q(;AgL9Qcbk1ES++@c0E-uu0CO|HtIf2bI;Dw2mhz5w~VUtd;Y%# zK@dbjTDlwQ?v&d-4k+7R%*i+CdM|&`8<08ucgCQClilr)NO3+4+Un^-X5p7j)xBu z`mCYSi6AJbQD(oNSZ;Wg|MCkI3Ih9juNf<@In4C4AzMnW8xXXOS!w~zNHH$Ll4at< zA=ClvGOq3XjEs#M^<6FFQ?(J|3C|u|a&kH|I4d~Nao&%98y*@ReO-Zba6Dd?t9hJa zB6s)T_L|2nn3RK(l8>()SP5_t`c1|%k@(~ztl1-i$I1L0PQdGa{4E#(&#pW$9RRWJ z(RpUz_wnQX#DTmh!}#nzW2OKyTnt}}68jbrPorfi1{$;HVkgWI5XKJLDPTx=8;B)oA0-lj?P1U zDOg#$ugSfIU9aY@Y#lQdldQDMSv_ukkauK}b`pFW9JH9L!SHH%^Vb3C6PecUxzB13 z7S97w*!A(wAdSCK5K_bK7{^ zwb`%rn1o^e*{_S!@kqcRDM~=-x69zMBhY9tE5Dq;n+X$+$`v98FEVY-t9~rAgc_$~oxTFM-vqdXSqZdBSpsf}O^fe4+V$3i zId^6ovw~7Wo{IqgDfk)lqq_7^RU{Q=at==D@HiuLkL?8j)wMb~9ZiLFe$aAs1R;b* z^MI+d>c$+s$*nQaTYMy>QU;I9?Are&qZ-nyI*l@2kNWkAygK@{M_tpUmOpK6esJq) zY@hHx6wo*&Xq4;Jx{iHe%G0?WH=ljDdtL#Z(_%gld5*=%sP*oVP!Tpy8DMb`u{;X_ zg+G(C+7bV&RwD@7k?LSy^+slh1ir%MbEI1|zyD)>yeR8(E>P(dcA$e&U_3_A$$T1y zL92`XAbipEnI^$(VWvE(lH%U(V5eIoDEDb^6>3|V6P|EE-xL{g2Wv6%jM{ymH^@u9 z#&9S&N8~!TUypTT?|g5zl=4G*1gY!Y^%lK```ubu!3aMkgWrqS!5#t)h^@~?bvdjv zxt!LPoC?*7F$X(KG@}SkZ+|5*sGn_~F^(A*N|amfC&HnvyGdNG-FX|{TueR=QUj$248)Q8@kwd|AI`2A`T?nV?u<(*O{;(N=krIQlR|vILEtd z4bvteORk8PThyptV~tKSrmMt9N(EJODg44dZVu+=MfD|eRTh^#Gjliv>Gj0*wQ{k> zG*1BPU%#CsG(FawcJFQ*5sj9jI_b|+~hxhpTDZg zPt^E-?*G@1+X9m>{`cpVLzs_t6Kv9z#Q$EJtUif}xCQgy0pVBl%{VwbTTbPkEZ=)+2ONP&0EE* z(M+g%6sZ&P+NPo3jCd5A@XOGF$qa7^SD|KR!1+)G1`g$TI=bnx7Hc|?eESpOb4^Q4 z0wx1;Sd6yxnnK77T$}5nXi8WAMcqu2Qeuz=BkZ<-AM+9|Ct}TyRC)DSD(+I?8%_E7 z#LgC#Fy`Fdwqm%^+VOCw<%UV2G?#qgn0@i)-#{#vnxlZ(N{Itvf5=9W)x{)x;KZQUiZF%@ zQqor_yOmFwVda^qQaa*#YMG@9a}0f68<*@;nIl}vIF|`9mC7kZ&mmxp_;qdTq7wQo zKXWuUJn0MWIkn0m#0#DIk9Y#}?b`*rF6XUS2MONVEHOj3Id6hcoeY(X`7hE;ssa=n zkM2!_Qqzo4kOlEilUDZ=N@6oK!4VTP$mPkJjnXh@hKoD_Jl%Y8xe&Ge;NIi4h#S+|fNybu~o!RL*XnqUG~J9MR|58dkX z@((9A@2blztgH3P`x|5pG#&Vy{oS%u4QGzOpA)(|e|eQ!`xdKsjS(+uhn6vC**U+a z##U*0uz0Q}cog&b**9(KA8)i8Rbzg)Re(+kmUJt(0wc<>gi?wZN-lw}M)7UjEUZ_~ z2$!q)!|5s-r&OBlbfT5PtST>8iOt*}%6o^InWvy}16C$_tS4<2<;8{|F>_~eDV1uG z#}}kXb2}elVc*umQ>*Hv9opQ_t=+Rq$g5}L!;{-Nq{~wmn}ATtay5imK&m*uCP}Gq zMEQGBy!AkAl;|8<$Z_8$*EB8OuazPC8|*@(pCQXBBVzNc`wjZ{%DbGdEmeAL_o0yQ zr#eGp$$UJwZN$<2BsH5hTht6FS)~RQp%jiJ&TB>FM=>KS#vAN-;%>LI zHbuP_>^Yr=6Az@_F7H~zS?p_q>{!lZQ>ryxA_3^{hQ!c_8b6it5b<*O#)>OYJvJl5 zna(dRPVK&~Feb;jpwZX(S3R%Lv?99~4_E{~Hqg`kg$ohG8ChIyRnh;J05gHB@ zE%x(6zl}ogz|RfBkny6lgR@woo)J#uslcGa+BnR!-*3n|XCzb4Qtf3%H8=HihX#4b z-V6bXq@JYM0-Kd@<1|566DQU&&R+*PvJ+#sZ4w2R-oLwtlY80no#^FVdR{8j1w08U?p6on$JfHVapKU=P2#^?w$hQr@nrIfch4>6KOD&~6VY;Pe&(yAH7;%X z6%jVInC5HUWj*49gxjIIDqqJ{tvxbpne_Wl&n0DGTU}lk zy(ZUy`SHe=uj;+T#d~qPAXPrIQx(|6L8IanRWQqVauIigcSe@?;OYB6y4mzr?UHe70%7-0TA+H-B zF2b~^Pf>Bs?5N#a`M4Euej;@`sc|_WO1K8-A3p2y%TsD_`Sw9cY+HD9TgS6S`x%+I zxPD+$#x~loN8wJAu?vGD#B+hQFCn_OvGelxiNOS^bp>o)5PEwcrLMaIR zVdS=osRs=&y}##+9S&toX-y;^>S=uO?7&g_%;YF!*0c=;WOj$+jLb{ z_Z8)w^2M2azQa?3YqX+~A>vg>gF=H_$X;Z4CPzxjB*Hst7jhbu^-drYls`DWefwsh z36GrmlYPDwtSc-7>P@@zX_1CIvUWbq3_>E-iu^dD13|fo8aK5;I~?=%YIcHQd_A=t z+NCK;LPI>w0|HJ&qxPz5Xv!mGb)V81c05Z+yG`}_{AfmJ%vu%UXVn);dH&LIgjSQa z@)p;MUem6$;I??Mz?ld!cg?n1lKOe-w0$2bHUk@p4%N9>L4$d?a54_eN|yNud5iD@ zp>e$NUaZb^{np)f)9frn9V}Z}ZUYs~$bOUp)*3|41!w zW2&#Fu|lyKhU4NmtlwQ?c(xuBlT1vo)qHX7hqp!}_PvJa4>5%T;+gpc7SL!%#KyDE zZ^ki(Y7IuH_)HOC8c@w-nVs_4pQ7!QXE|2yVv^Q!5wb`sZz)5UYF91WWy+71&=c`x zjpoX{SH9$mXT~O%PRaY!l)j!)+eORC)!*abQHP8+2}pG519neX<;x z3_h~YP(MGZ`)D$O05`II{9Y2-ykk5wx2ZnW&iyFBUwt*(NVRZ zKMrj&K2kaP0*39)#@=CNB2Sxc4x7B0M$DGmz>Js`%?E+u^GNb8#c?E;8-(@A(%Ruq z?pg>dyPMD5Xfpnwisp$Kz@C5IaA~kqIx~-1*52f3X9`(5geD@u;b88Y=5?ZeFl6P;R@7{3XFcq8XYN(jz8N^qf_o$SxqtkQxhUg zv@9-AxwojQy;#aUU!jLsPH1(+@SEfX)(?oa>9Nrts-SHsOWh@b;kP} z1YEsgp`g~9Klo}DzbKcN?M|^&hq)3*GZdr)EpWK5OkY@3NMA7XEN%!v`3)+=7j3QM zm!~FM0&gEG_38#oaqHsAN4EFR@#Zuowf23T{W?ESj-dtBwF|FKIuMG#jz(<2NxhzO zU9n<`w9Z8=OU<)$3uD%w9Do{*vgV`tDK(F}c+$M|GR{{sIzewS4B3mbtNkQHr^7hx zle0jCU^9aCsl>z~d)OA_HG&yUND;R#INNTgEUO;F7PU_1#?%El~d9Q zAKGNQ&ZJ7r1|{0;Xvdyuk&QgOQlaZ;o8v3&llAGEJTbqIfauTHZ`Mm zTyM&Y3~qINl~w!tb!R!_pq8}bdrMWnH?K{Rg(`AfO{w>`bK|q7B;w4C=C`NEi>mb3 z5ejYJBsoHTfIW=}$tDwoN^a(Cg~?R@EMOm+(d&Fs7ZCTk8$ZQkQ%VsBd@OA18q$^= z#x8}q(;S(lubtP4^uf3PcF2}4 z6CK=6d@`5KD+Wi0Hmt0tF{A2QACbWtkgqi4*8Ev;A3>g@3{w)oWccxGAXQ38?uilw ze?c>S?riyH*n)3(rvZ)EvAP6&L+R%6?C=UC*`n=L&S~#9FV9jyLfG3mu9O4Ag`%|a zZ}&GOZaFdJ<&rR~XbKu9!@necI#QZ2x9>-F(k(_-#^5JobZfFH&P5Igxi{gP!(AD! zi_9FMzYmsPTOet|Lz~X6&i&{C>y;jv|7Q;gF$8fiRc}n^tVe_j!Z2L3ph2D#B2~J1PAUN{E;i7c=tpFa+F> zPO~k=?t1cs(SdTLTWj)_`P_oa;j>uh1s!yLGojn9@j@Tgf!$kY&~B>U0wlnZG8- z8$TxSlqm;zOG?GlVPKvfYNF=b3e!PgNmQ!zyk7opA&#X^yw8G-4Jbq;llHOssDj9) zr@aH674R_9q(8)v1YKa`FLyQdCHN++bcF;S67sWI0K|VM`sK(96)kFyCSyleCny zPKU#C%^&g8qGmZPTzFy3$c}F&M(SH>no0cvqW7D}rwCX1qC-y!Dx+T{m#Op=3-wkK z7YPHRr4#-IcOZi;whfY2I+{?i`&KU8yfFF&Up5h#I*kSbztmXw3sa5HG^QKoG#z2G zc8a0o*TfVR-Du+ca?9gYGhd#2RR3<&6LEWTt30f30;_0zp}3i&b72hkp0C%#ZXORLoGW55m4@4S)Ud;s3-~nIeBI1!8?<~ zNhJUFY>i+{>N0*r`Jqtm)!c{vLTw8zDHpw+xJK6ET~|#dPL7M=l1H;sC{pk$RS+1< z1BczM4kWfB<$TkaGh$_$#PryN05QclB|5_q!QbCMZT{?peEiT%eJmWy#xAZ|m`QC? zzB~1-hy5YyM|rbL9pw;pnu{+Hh-50cnm^cyVV_cuZ#6c=zdYBx64T;e?mt)EM8F(Q zXL^6S*IC7IimSj;IcJu_-YpgS6qPEG{fZQJFXiOG*mOG}eeTq!nZdBh5G*jq{;}U8 zfwI&CzDE>ARN3@jl`!99yRtuOR_OGI?^Q{K(AC>CUh(SBF}QmYUe1(mgaw*K?$Ny~S@PV5L3>X{>~XjuS`U8eO=S{AKho3J- zcRfW=6VJNqUh+@$)_u3)uOTP0;+|Bh|6BxBTfq4&$40+Zb@*!=L{hdkn9-BQw^FqM z1agim&VFrcIU`eK*7{b^FWuB-=Hm(tGuiXEwg^BzcR8r@8cD{xZt2^JtHy{Q>N<_i z#?d3~(`v9|9;rcFUPyZ-+n$+re?4+s3Q3UnQy|BJhk4DWU=!_oO-zt2?(c{AzL0;( zJy`z4@icYUv!veAj$BPQ*4#3#3pqAKc|jAQ*sT7TaR*V4yrNwVR3*Klo|>hN_% zL81B@9n4^7z|z#IouBjIP=O|g%IEGL^(HL5#dd3qd_^gL;?bZe`WSq4&yJpJPUs`& z3)c3}F&g@F(Xo^pbOPGz#9`pe(D;}!Db^+6ll5G2Nn!fuX6tNtVPLoV2W>qzsg9_W z!o5KP1*BGm(ct_i0~yU)qg>~=P9T^cxKr`?O~@4PHUM9*ckzyXd#&q*EU4iRRew~2 z;#ad8cC%#Xh}FlNP?NI|8mw=4k5YzfF>7i75;cxf4IL2c_ ziM2ERWP4LR1|?BkJBEZQvS@E)5gy5d2zTN=$U@RB6;gF=-~bamIAnm{d;5v(1xY4l zHgBNZ4*@>SWQNmdG06RZF6N>Y6&FY}8(CkroXlPHKtG$hFql!A(P?@Vu8e3~;c zmX!IO(y>2a2BPY22(v9VG~52l?J0E}NE1r+mN#`g7YPedJq{j!Tziz!GJ5ZdxQdxE zkG_*|qJT4q&Jcm(^Jc-w@LF6-BfEpFM8DrcB}$IwOL$ZkTcg>!`-Lc(!`=UCiFrWca4i1$+_ z3~4vJXvlL`C15EGwc`fi*r?&>Gut;f^MgFW5Jcz3`IDytQJ(Va2jhVG*YmCU<01;u zLJq=)-3j|L)6ibsEXs}fv8$=Gk&6Yrm#p6YB(A>u&fYD&r&^d(`;(MRq!f2)pm6;+ zV&F^eM%c|5WZ84B$#TQ^jqP3;eIc}%la!f9P`RG`w{rc9>`F$KmtmNOlm-!s!pl1b zn3J!S^I|Z$l6y^1_!Vg|zGI`tEreHi?|PUP5zXwc5!g6>w~-ll3>qXnB#T1F#8PUt z2;!bik`vS{DaXCN_v{XLg)Nq8>F;7VtSmRJ1yTy4^%J#&0NjiIZd{=;*Sqvn&yvd> z>XDn$fQ&l@FK?5kD^U79NqJ+dQby{u+b3H39z)J}CLE7w+xiAmD`GB%m2Ipi;8nyy zP8@b=-SlVvh8Z*z^x$`2HbALy4g*XQy#Q0r<^GWfoqUe(wr>9)CcM9e<@x!rBtvR1 zf5arWeC|c`JDkQbv$wMi?d9VC!Ll-8;83sm&58(eCd#W_A&zY24{qDNq~H8JD+U5Z zAG^4ArlSkO-;2_t_QYR4Er-x9M*Y#t&6)N-_;PyVSS~I|A_&{8S5Dq!a0P-@O}jOb zi{#K_rnWX2Y<2!N;B@qhzd@6vZ*(}ov@*HeR{2vk8%h0VEK*dtOb%Z>9}0fuZ3R-_ zk*W^i0v?xF=eLymP~5VJA%>L<44uqmg^^KN-(2jZq_)BYR6~Mc*3B~Ee{3e~5KC@) zk9vJIqOM9Rh+Qj9=>NKN^^gi%Z)_V1N=Bg{gzKR$31{1pRaRw}?;tj9O==l7qgBos zpT|_CHN?MNB|MNE9YG13Nygi#zB8!;kz@jydPtmOaDJX_d!T#>| z2}f5_fA7+uD24rKp^{3hWl?D7)nVS;?{Wd0sAsZ7M{*b$@$m_ys-gvjW% zh)~K(Gv3Q7QKByJqDNK55A30z3NC(ovpeyIkqaJjqZ}5qYn4-${Dw-M1{GhEC1LEe z)_9?Tnbiwc+Sv!uNsFhi+3jATkmA8OE#|yo!@O3~Q1C;v)b9a*cb^iXq&IKJ31`hR zG)6D>zfF1d>L<^!8o*(gqN2bN=?Z3#Y9>f)Wrs$jBuH}$1Y6m}W4=a%hq=A^!&?!U z2vG?ulH(3SBj-bxSQ2iCQsIt-{>&qvFCibjM>{JEPWWrbSjCG~=UJavj743b-~xFA zG6GXOJt`d@UX^INv5DcBFtAe=ZA7OODD(^SU985`yNGKd{(+emy1lo})H3aAb`r9fOI4ers%m6$SUHc3Hg1UthxV#f3uO*PV`e zt*R1mqE6R(L@a9(DMZ6q+7bmH4 zZR1n6kh;`LYo}Uu9s0I7?yPFC%ov4_w8$6^c35@%G7jzI=>QFCkxx?wrJP8EEL$*f zO`mj>T;UJx6f7aB_F9mpOCm+DEn3sdLvHP-X?1P3>}=J^PewPccIBxxi4ho= zA{ftGMjo$6YG}L7SSRdOR699E3lt~E-ctAM(To{O<<)4l3q2lJ)$3T|qNV! z>~BWeH{Ri?u5Vi)@4x>d^E@`|k2MMXdohMeBlgef`_Iwv|93Sg*(kXGml&07e)hlD zok9Kmz<3o^tKqaWq1Rp`f_)65#&Luj@niHaPKil^8y!G-iue%3)7eWX5+o3AMK4BE z8);^zGyF$jv0}^28#HV$G3>6d^m0FLOj#r~NIAk7q8g$bV)2W@6yt#vKyC3d+mQO) zuxf!Ve1~?WNwQtPp~MlM&91un{3PABNQ0>7`@?dbrtTVH%2IsAyx}6Mb^8Teq>P#w z&3NUrQ+8JKdHud{!6C@&>kWF@i+6`prYoeH(8e;5MVXw=WsPskuEn1)O}*3tgN!%| z-eTTn{H!>f5|0RIW>#|Xgq1wqNpuGptR5;RL|(&1njy+&`vM6i+}^@jugq+7fY zXFf0Na9eTR^YqVr&wiQhl5lKd zAvf_%U33c}*pi+yGq%gP#tKqHNin{?mJ`uZe5wRg?z+!XtWkckRsKUH@9@d{bN*U# zccuf|#=vnn6XjM^_4tmL)eEHcjv4rUr3*({7iEaemN;`O-6v#pkCtc%db&lQAJ5L;?!@J8V(t6en?zlE|#Kkcqdscncn!)t+xY3`Q%9SPz#Edbw zRKg`N?eGIP4GOA>L4fo!8sHkJuvfZ|NWMOxC-kgq>cjTL87u4a6%LG z-3tH84_Wyw%0ZFtMo;m?cwhL0J2_IU>dgKG#jDEDkNWJyJ7GAdCl4wqO1xhCNh*x z#|c^xPpmQ1tT_`_`o!J1vQ@79KsVL6<636?tfZl*;e zr#2jYcqgnnskIK#>=RNMMX?qYKnAy_l|CJ>|JBXJlGcpRi_4i93ps6DM;76gYMd{u z2=)3%tLv%|DFwc5vz%{KA$8;NSYQz{gHoOc7nTCq5H)7Sn|`ZZXaR^+(uFR}qf4_I z#gb%p-!neyxA5zsR!q!%49ry0oNd9e1$0oy_D9&bNr)@6C+5M)rfe=g1Og^x)^-o- zU%aV@iN2`m5U70M1I?`p{WVTJOQt`;pKJxFu`90~GY+Qk4<)(D#x=hqg&VXkKsO6m zHAA80W*gIQJhDfaLO~%6o}N%jJXbr^Opk#V!5@k`iKb%Ht&w~gIwBJCFo5)XEz->) zkQ*FbNv0{}Ty?bDjB7mb__(_dWvonik{}_o!p63n`A%v#W968dSdOZ8A73poXuCUo zz8)XxWv1ryL3@6YZ$T6sR?;ss!BzGN@#<%eAvH@`ayi0@fzEfw2%MZ<@z>d^dKa>~ zA1Op4ItoqO*NbR#hZpL-rDYWOBpkET1FN{dnGDN3ucN~%8+-A)pw|Axxbxf9^XkZD z_4RP;3_bJqZlTy$W2(r0>t_mo%DG@tcF}iT#2~Y!VLj*B7D{`U5?fRvS~S`fg}w^R zMn58+Y14yo4zzGFoA-T#rdSh?l>L!@N#^*-V=a~*NTDFh{plXz&hYK6*IJ9Ea-7B= z+P=ZF$^LUOH&rf1z3kmTaL=TFUQ^lxA_Gt6{pUM6Nxg?L4n>zgny)F@vE#bXUa&wFD!{KW?-uad~Az3Y5zWbNA$+oycrf9DU zOu_yR^{feLkSQc9(cT?4U5@AQi(YLj zgbF99qa9Ny2DG&_>I;zJ7__|xNfu*9mS)s=$_Go-_r-l}>+WZSaMwO2aB!b+>ZFBS z(2&$pm?yh1(5SS@o|7js{J=RMV<$~|lFK_Lg8^wtpH`=;utf~r3?^;9lJ6Ee2qMF#L<()$^|Xu2jlD*Q z|I8wF@T0sPH}w}v&_+Dom)=1--S6bSTdhPxELbL}Siy&rC!< zY+7Yne1f3n6Om9X`)o?I5lI;$!<`Fi19F9+ZWWjbM-j&rM>7k%wW7Z*-EMtPtY11+e7k#Gfi~jJ>atl(U6+ZV(+#1Qx+D3A2nyVzvvrgNaaj)Qe4?CFsBxPH zPkda4s6CR$4cV;jb`@HVv_b9k7vzH?YWKC;u<<(9pO%!Da}tIXrC`-UwlN58e69_7 ztB-i3{2HAosj)`C8yRB+((zF(B!}sm@2?ai-he!}oSgb1mA2MH+{GU=>OybX3#PPk zVm1KOw*0l~m|{=rQ}JS_&O(qkjUzYJU(o>WSDi^;*atvuFrrRw_#PM<9|h{bFz93p z2EjoWrZh~IchJ=c?B;`exWE}rK;t5xO}w}>F<0#$7J@mYiTZ))XhBR?^dXoYvDNb> zh`JW^hu#Xf!2@xWPT+yin>n2sR;_P1@_n*u>qqq9E#$WaehmTuhOOj&;n|P@RYt?Q zy_3WLgjO04n3yhJa6vj7uHIz#tgK57-ao=~ty-E0``aHbY1I#8I|0+0z zq(Xexkm-5k3@;w`9)>mIy;wIN<)v^SP_~HwJab7=9X%h#pTuheQ~9AKW!13b(0=xM z3Wl!=OyOSq>O?TeCEh-y`}jU@^!JytOXY8J#;{ob6_*aNilg3+2_wG3G4~PTtMAei zeWCak`X$MUuEk_5hLDU5bdl2D*QvO1YV+6p-2X|;0tEv4D(;PQU=)9*+2*24MW4kx zk{6VT>;^)HTa>>-58ES#J^xqc9kzsRB~OfcZDP_+GOQ=H90!>$V#b8Hz%dE@tyfi^ zw+b)9#7=juVhQj+?5g4k@RvmC@akK@jUIAzFesUqF)oy!aa~OOdkB$i7F7K1(;e<{ zLidjIR`wfoUN8*xUT5}mzXT#l7nh@9lP@%t3jFlNb&rrlmj5Y=pdSc z2AT3y;tUY|XgwS<_VrVrfUh#QVSFxb!P~x3FS#_?6sy07vYfVe0iy5r!BOt`%Og#E z;Twz^AE_*n&4=)(J36~2sWtDsse9gg6#wP{9WBQTP(qZ;T z954^!@1%nS$on$y3*)HCq;f!wY(6CCi;zl+(3HV7e0)RYZxi*8t2p5AgaCtDe* zcokz5UUB9H9MC0#N!{1lj(sFcT-|E^-emzE2@KnPQc)^orV!dhfxo=CE{fVbF+!iI z7EZF|ho#D#PuSyE;?u zvk2SA4j#*_zK#Ybszh_aB&gIhaRv09R*-}DgojWlhaqoH2A1##N$C#KosX9ZY73=y z1Cz(a%8lfoqXNIjlsSpA^`%{TB47EJECSzETlBC7o*ZUGtsf&VZ7V7hZVX8Sc zpDqDoBugLlSs!J(d_;2cR0#PAPEJ(gNO3>J^w9uq6C<9-tebO zjC>`c2!H~Ck)EEOl5)V1dB~8tTvZcL8&+3W0k}cDT=n1S9wmRO321PELXzEj`R@0M z7tdLq0u|t++yWvJG9kYfLuEcG8K(jK)8|M9O-)UKYrKFK4Kqw^ogC>c``tn9H~=CA z{=1XtSUtdM1E4O~vyG6qv#$yH@18XEuUz=;GXDGH~KxugdU3p#5B=7%RJ~4T| zD3boOoWAH`Isl~wn#$I13#nA<+yf=}SQ>}KzZVB5-CX~Q61cxmLPZAXEYLLaBj|V! z)D`rYsN)WMQ(O*v%0Mad*MJbgud@NkB9G0gU~7?JUfZ9&QlK|BUu#jfMWm@ff^m*zngIO0kU%n+0>sIL%c3$8$fnkCY3-FS;3Yf^VIS82{zPq zMF*b>$Z1Ib4ZM!t)@Tao5Br95c=HU5r)=^&Au0II`>O>&AOg|?n4@fm*tob-KvSz` zLHR3O6^hp11~@xf)v_uFUGRm=b-?{kf&P_qfM8QqRrLfOkdOd+JDA08qvPfFhLKfc zV`I=eGzo(r`M+pO^*IpVFI+{26AC;esOhY=-hsb?djAMWi+0k0Y}Mm(S`9PI2;3O} zlYD4(q<7x=Q83~Qi)hiSTWcIKZC3u%CHSw51s-x>f4qDTkU8#H8FEfQ>5a=~X2Sr$ zWqS*a$KX9zou^Aw0E~~O-?2B^571)BDJgrQf|J2l(r$NEu?ZuUh!hnUS6$`p(|OVo z!%*u88j?{^AmCBTr4P>1dOhAdW$}9i>+H_g)5cIgi=p<`sicHM2v~3by;3RsToQG$@5i18v*IhAN?@9L`33}NIy#}K4nMz&x$lKq?<1PeD`u@?M6Kn_bJS*_2LG%!9M#lwypA)0Da^feN{)pCKo0K(;Zu>*K< z4u|v8>@o`~A8c)Hn|>J#M5c@xFO<&LeTvJ>%#4ja+ZcKioFG>O*hMNp%rZ3hhEi^0 zdpjsFP+U|LCCPlYg3tLxFmHnQ_o7|;2%!31x_SVh4B%MEOkUiaZyy%6fR3%JN~`e1 zBG&+31MnsMeg64acmVxz%uD#`uVo2+^UXgo540R#oC7z1E-$pn2ipAttP(K`ixS!B z&W@>2vPO9#&%P<~66jQ00KkXtSSd2>KS+0G3^;kthpqF)DUn^!F(>A)WIZ?72L5gIX^#dHfVxv z#sZBbZQAJo0SiquoC^C$ywQ4vqL2#^3x4cVy`8wje6pvZSRI=P1Av$_Cl=fJ^% zMF(M6Kl8^PnD4B<4!WT8ti+djSg84L#I~W+X5?#A<(jj_CO^XBl9QXvrfE=UZ7gWh z4r0^NZa1hK;@W+HWjFqo&V|lXKU~p9`d@T+U912C48PQBlkpgCjsK(FIA76(Y49&F zfhx6I#Us}az@m2o76#}Q0j}#jNFtF=UEeJUNGheHeuTWC1VEK`&^I-m$BBW6h=`qi zW|tf^ZiXU*QSJxmLqLlG=nq-{Fs0nQyysc#raw!;8*Ox{hW-_13q{91?+faBB6ku& zuRcTX1w^TkydlHAxmrs13}z##4o z{rB+@gS+d~hW%*<-HvqZI^oO58BOb$y}PyEAV8x~2fdRABJshzStwOwd>{uB$#izh zRLkqfKeL@=uP0H&!?CMDr}vulCG*O5@jq^Ynq4bXQ_9~ot*jXOSq@-NVQBV-6KJzb zsT|cv7b4&-=Gt6XINnXw7)eW@h2ojkYy7iJ5Hs-XerG-26=@e&n~W2n&=M(u4S~aQ zz77}{Yp_!QZWho5*6Ou$ey0VH0!n6IbKU0wfxUguKP9%6>ZaoRSqEKi$nJPdd) zOVtK&Ufmp_Y)j5-0a$?XWiplu%M6VkzGVI>Rj1Kv32Z>0O4Xj(cx|PaECxRz+)C6c z9{>>*An$f|o``CGj!^Zi?$a)85q3 zt~SvYkd#vl05Bh5VUlq1dp+FE>UtqHYIb^p-kP80YK$VqBN1$&o|Z#2+7oq%Wa*v4 z$D+bQ1O}*(TJY@vQ;)Od9SI5a-Ou)n`1jxPk107hf9h9%0RBu`8bI@1@3|`=d`6N!2U_(*JmehY;NTD*Y#jxG9FC^hOT=;Jw*nLRxQ}#uWxQ}UIhXk zl2(&Vw__N|>vGk!*hkGEOg%JRXe8#pDVbCC?4-fOHFHkWd;o<1}y2L3@j`x%A^{QQG z1z2>j%Q_RpOBMV%9Uz2zg{|)_zyYqwfz$yRQ#S{lxX2o4?`AE%^&Lw||Yj!Cb9 z{VEXbslD_hq@+Ws4CFcIRZV}V*e5869u=Zw5O9|$zz;e3(}rC++gl7;>H(Jy>}S6Z z=4!z*G+cA1_Lheia%BZZQ-uaYw^G5Pa|Cb;fBpIe9B5h;`6Nc&!k?%W;DIJ+>3n2- zLcI7YzXN*(pm~l0veiI;Kk&Z8IRTHfc4%nG{XQl-`dQ7dqor2aG{} z$>`}Lnl$MW<9M4ebVrSA4>2XZ!8~Acj2YPk8y3me<`;fGuU?F$u)x(R0_Rj&Ss85j z%?bPex!@!TF{Ba{l$6ISodRrZ4uJF62V@Rrjn1r}e)u=hq9e2-&hP=0lf^qjBPiH6 z`1nXa^1&MF>jjWTu&V9>$CHtodKaKusbLtuhlkTBFQBjf1x9Oq8EjYshXte6 zu9s$E{bx_6y|T}sv0@F{&}OtgZTvoT=kkuZ7#JFrg+ST@Y}I5F{eY6 zS*%uzAF9&oNWt1G(1dG+yZWnjl@t>xfcQ+oBO*%6$vuEWjE={p%I8O*u73oF5TQK4 zwgJ1RBk*c}N4({Tm)Zo=9bX$dm4cI#lY}JqeH_Is;GF<}44ig!%R+i^p0widkO@f{ znZ;HoYd{Rl%329VC2g_a6|O$_6YP*lVGcOI0#J~rUg8lP%S5_DEAGFSfQWoikqRA1 z>oYk&=ZfbM7j+@4^GA+%gE>aX|LV_+x{<1ny#QF}|KAC0_%(==J$=^y|8V#(&II$H zmKfgmpL>AvFX98P{~MVBhU7n2`v3m@U)uNo{vBO2^oXVRY?`u2Z=U0w?=$f8UQAB3 JLRioD{{i}M7WDuC literal 0 HcmV?d00001 diff --git a/packages/woocommerce-trusted-shops/assets/images/ts/ts_product_reviews_de.jpg b/packages/woocommerce-trusted-shops/assets/images/ts/ts_product_reviews_de.jpg new file mode 100755 index 0000000000000000000000000000000000000000..349fb857933289cd6dc9435f96109296fc5466ea GIT binary patch literal 80141 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 V&_Aa0KjIQw36B3%m%u^a{{v!>oD~27 literal 0 HcmV?d00001 diff --git a/packages/woocommerce-trusted-shops/assets/images/ts/ts_product_reviews_en.jpg b/packages/woocommerce-trusted-shops/assets/images/ts/ts_product_reviews_en.jpg new file mode 100755 index 0000000000000000000000000000000000000000..d01dbce54c00c67faaf95a0dc804bc6665fb4777 GIT binary patch literal 84405 zcmeFZ1yo$i)<4*|1_Hr?ySqCCcc*cuai?*JKnU)x!CitwV+rowXn+Jsf(L>I2t(}N z-1lzYyWf9(Gi%M7Ig7*UQ?lz<+p130u5&Yg^Aju*FRnfBWwYLzkq!be+7xotPc64zB zfz8Oh9UYw91-(TmzY!O_{rxqWjgtIZ5wN`o<%6%SlItp~kxM$efyjASd08wtxOvF= z1XwwExwr)cn8`WWIr!Pw`Pn$QSU7kEx!DCdImv%ql(((9Sy~BdNXh(Y>-I^6@<*q< zyu4VwxLBRttl2mO1O(XFIoUWlS#C?PxcfMP&AeHh+^K$2kOH||xY@dZZJnLSzfv?a zclH2_P~IZ_-UUaOKgj+quYM`0to)ygIy!!3z&En)U=7fpc>k8LyOxg&h)o0J?(E@a z0lF>ih1J&9Qc#9V`T>W4B%c&FA2$bwG`|D~y8u5Yw}3RSqyV1;&x4AwtJHI9N zmHJO7fP{>I2m_A-2aAe!n+SvOYaRdw77iW(5eXRu^)3K_2nz#%LqS2ieS}4X`g3x) z3F;Y|BwEgA8eB3~bRm5Ga<>R!VQwiRpkX1x!^6X&z`z3F;IXg~?ol9em{HCkJy4J1 zq{2zm2I3RAP9{ui71ZN;Bo#vOcs-HtKdF)6;^EVvZfMMXYfkgZO%mnMUHW4Xx75>~ z;9i-VMF2Y7ZKtu|umEC!FJCzBmF2&a%hc3f(n@5L)#D+imP{!CyqeM^Mkk@UOZKiu zwf|{;2kG#-+#|iv7!+B5k(9pJFLhX?*wN>HY*7@~R+PdtBp**r2qiy{NO>y=z1{8L z4mn8;{g~+0z2I+)xx<0=mi{25_I!$L)|{$KeH9aQSRhu>Bm4hZvUCnb3`3f+y#g3& z97^hNIKAxP#M}ExxG8Du-OKZ^&pk4f99W@|Qj_}zdXvt;@JsbNH)9H42=-V!mrIKPi^f^m3&v~h8 zd8<{q+lXq1r|+PiH1=XH_u>)n>WhH$^Ngf(TG_?-44?KsNN%QhhzXhc^aNNnFP{cZ zkqI7)v8|up>mPn_p#TSrMA2QaCIedQo^q{}zb@eMw z(K#~Fm8YV5UOJx|kuqgx?W0z0SSUVKOCEg@Grc@KiB!<|BZe8W9k12=ojh# zuiM8zG1z|-+1~*APdfA$k^RL!{^U^5PY?2c#G!xUL4MJpzliKFO8q+>`i)Ebiw^y7 zxwOA<=ubfZa}NDa0sS3^RQ}b+{%-;L8y)&TbNYV+=--t3cV_<^4*kXK|H&xy8kA~vJYs;f8D$Bh{<&|=qO?6;?Y@W>uOil+bgkF z><43_z7^(FlvK2Txv>aB2SNu!f6xn!OpTQKv(Rm3kBpRzk_;v1w^xNfGQVZqCdFYT ze0_s3r~012Ny%yc_5Su+@hx%SmVnY%63SF^4?T_)&sXn!Apv7}3f}-e^TAy(j(>hm zC0smtaNzau1`u9z1K6uNP=w2@Khgc8hd*flN%J4&Fcn^2c5REj8M^^od#xLL5ZnNo z+hR7Igg!ph@X=xWa(3o-uGuCQa%L_k&_52$R@pT%S}ixxa!_n6?{p5cVXA6vnx~&V zAK!iCHb{kQS*|GfG{XuTi<@rOq+m)q{wYEReXT-byXA;^DDt}b=DL+y8aF?8^9%{{ z?&ownk+4Thq`N}C_o*CPwd)TBLo^o_7Aues?{BeIEec+G>?|hFLV?ZY9c}HBP1$9O z6p3oPG!}+op-Av^@<`CEln~ppv;m`RCk!2u`1!Pm#uHROWK-=# zLC)Ivs_4kuKlRBV2F3@1SHdF>pAl84oC=ajVUa=RRTUL*OiZv}|HD?mz$>3|SSguP z-&fvvnA^F(_p0BnA#UW^;v_l)r=KXK@ZrnedN`JlyLyZ9C90y4j&R(Z>d*GzD>9oo zZw2)Po#Z}2uRDk1NIykM(V^mV7(9~CcQBsb0Ftls)#ru$Wa?ruSdJ|$efTUV=77RN z<+8YSc0!2JufWtK9=j9w1vUmEL*qbxUUv3QQyp6hy{DaG^(PL}R_+#>=7w3vNesa~ zq}jEKgq2f5$b$@4hwqJe6__y$PtqA74{o&;L~^L9 zX~8at@zOwC2TQs^-4^yTZdpgYIS+isp}v^EY|p5B=WT=XE8S4CU`KPSS!nV@&F)uojBV(x2l6SQ}Ej^XOAG zc75;3-L$f1mi(f*bZEvI92UY}nJnMhg8X#m`KX|1}O*Q@*VZ>=`iNhIzDA`*YD zsp^Q}v?VGlcDhD}N|NM;Upi*gYrJs;S^_C5#OEK`uo!IQDT$X|WKSHJVsy?njDuSIP2lV&sB|)EQgJ99U!XHGAtc1wfZm zfu0oApk;|hWt?~k4Yty`kGYW+C{Z_n2>{IU)=T)tpxK0Nd(JQRdL8Poe3>XNO_Gk6 z=1BX$xba}UtIXIW#?PxIYq%ic+KI8a0r1brrZ+k#x)_HKJe=G3UeL89hNohcKBpZw z_PV-X>GS&h4PflHazn-@&bP|vTh9&s$S(TwglFsg^8$~7lBb;{yeIv)9xT(2YSe&l zh@VZ`Qq2BH(D9E(X8)~`)Rxd;bSmx*{M2W@q4E-S+O^v6N1%cl3FwqFoKC7BZ>dDN zYWO#laWAFXVM$gp3lmG`Os>Q}CCpp9Q%X%9hrBnT?u`1l`gTtIy~X$qAm2qS-r)vN zdc-vpK>F~^>)^ba?91Z*@e93SRqa3B^#9P6ejNlTIj|unoo%f7U(gS30CNv{-mAx4 zMh$!cu6H7B(j^_;01h5`bp{J{pFi@X4$AaD(YpeF7_zQFvUMUe1Qx9E+zaRWyl&;T z4%YNcN{AgC6Uq*Cw@978yMdYs_G^lbQ3qjs9KHc;yQ(fF4F=`XJl0ZztcW4eB^*2U zzp<>PyJrQ|1!{D?wHgsEMdz7^4ZoxEShuo02oZU>X2YGMd0bA%4TqvBp*nm`5qJaG zXfQ9oWBORDaeWrA>Lcpz3C|r0hirzUdr_QUieiA9)+t2R>KEtJiAqgI{V^$ij+~;l zJ&_eEW7!rMP&!uz<#ZI3E#wjbc_3w-J0oT*^j_*{1jPQ(XYA7QEz<@D6Io#2JQ{+9 zm54yUkD4Bi0f?zxW_@a^c2~#ey_<|I{>vgW+{-hnB=Wct7zckrHEeDx`lwb3FfSgQ zH0J~3u!g2_5k5M2)-N^DiZ)qBT^QW<9`y0Ydp%z=8qP$*t-{pn44PQyA)>LmPGK(x z#?thtQv_i0arFyEM#3@XbTpb8AEAt#WiQ1?z7~oPht}gjjch^YmvIXCGZT$Qri%ww zI!SJqS&q#ErOmrlR6%*=4!xsAyCE+wfCgrRbqWk_k!tYnMjqQkh*U|1eU(PC`JddA zGqa|$tD*&VMKxAVv>$=p`n_yfB8CL1=hYiU2Me|zKouwMMRztG$lfWU%XGk96WYC} zRU18F<@Mh4g)rsiYeT66GOlhAsBk`nt<~%OLX^5f!w_(+f{OL2ld8`wVGcroQVP$E zt{UUZG3z(yD^8J!N;9wC*SshnJgSiH2UlkIIgS~WkR0KjZ8H`o?J9)%31Q2xcrS?T ze6*|w;CKi3E7zVP^58^v=e0yXL+eAQ(=hv2X z`(>|zBN;~7<8B=xg&kqf7baP(5h^FOcO9vd?e?{zeT|DYww^aI=8=Yt9y1)btO%n^ zOZKV9#2!zz`YMQ>$yCf{g+lT)24sTlW?z25iDodM@QdgLwd%HbTB#efI<0`45SV2x zHnGtl^OdCtsq8ax3>`5wd!nj#mFwe!LPn`tzvOj}!OTA|qbZ?a(_}UC%blU^Ei23p!BEs7NQDv8gL2zQ>7Gid#z2U0o<00QHiUP{ag|F% zz4BO~VSx|jv~i!rKcGHwYVma=&Y~TS0pXi0S0t`=43yYwSE~munjTVFh=9BOZ&X|k zvihU9GN1SO_#VuuJeOpuEPB5F;b3cLnotmH|R>G!evB>Jui4OH;AVq1Sx*%=iq95XcpnsP zG{V!IBJQX}sVOA@UEiGK&kSVRyYZ?;>8xr8#YC*2`Zc-fdbf384C~if?M}VNF2BbZ z!Nj^2?$}gn0XK_`#o{t*SCzcmG`QyGQ{X5-?69F_DXrw%P(^|UouS?FwJYNdU$_&U zj-{R8+;QZW3VHSJVR|D^fYHp6-IscpR}M?k=PiHG)m z5Bkw#6yNZ3WW`BSc`D6NfUj3%4rKTc`Zx6%$JURIwl|gSl9sG^DT#dFE5Z^vZ!aZi zc&o6Aim<5cBp5YuxOq7Y12Ou$I({qjJ#h`{Ax-Tw~&!(QD=bX z!*;smx+$u_J{)Xc?QuE8FsZWo*;37(Mv6W+WuFFGjmu)y1~pJ6-3x>GlXAdl?g@eO zLtQDgmeL--@~mKn!D!>H)`mTz#QmIxF>Su**c41e9FCpZ!68jpH4}Px5%LAEi&5Z^ zbLVUuHeIT!+1j!edo)B8$&lH`t+yX0 ze6c(^y#A3rJ_Sj8s555Fp0n{Tw>2*D(-|j4dufa2K$fHCn4l0Z58x76JO9PP0ui(= zgFbIprV?+ZdrGm=m#}fsfH)}EsMjiOFKwKpw|CjLouTdVQcRXRTgGL%na=svo#AAC zN$>gQ3;jeH?6gY${j~%7&k}-!gx>Ks?Pfr$vx1nlXz%y7vCkA?ygM{wj1OF2=RmHu zy_GUMBp_tV7(fM$V_lX0#u0_Xk~-Q#5Bj`IFm7Xixy8drWNFp{&!0GIsh#EN( zGSakfp0%RUDW&f!kMNYH%>gZ39u@-2Sim_mj2jl8bTku_Cmj2WdP_PrY8E!zRkVqb z?ikpp0qyP58*4`Q1I9+~*LtvJ01V_YH#WJeIEapWrClR`|mTuA1eU- zp;t$@bMR*lod^2STG^|Ym^T0v(SoO5DKw6dOS?(1XUR;I=esG$j04{d0AXx*o<-F- zqC|(RF4SeCZffFGr%p3^)8uZLY@KP@<1j5F$vEmU(|*Hpr?E~ny!L~LD5F^)agrvH zQeEjimeRb@-6iaHdxWqTFb{|DG6mgP1IiytY6RT?v~8j{!>GjZdKYoH_>$&%PdCYZ zEUNPxq-cj$b5aOQI;`mah7gVHg7HBkW?_2MsE-CJ_)kTv7}Sp#^7OyGix`l71?uEPW7CX zSKGD^0JseKp`I%=6YkPF%vJ$i^Wqol_n{pP)Rg%AR>_RvG1VteBdj0CYJ2Wln~rcA z=@IBS5tgJoO=CHLkj+m%i@TEvu~rG|bMowHs;cGexfR}@DLb`q*E+tIrICo&^JtHf zZiz5hkAg1QRvOH(R+J4_U&)Q+_6K_$J)YRg*YSBI-FC1rw;O>6=Hx77O_^C zN2F>hv=DI;pAJxIf9k2XZd|2Eb2w4E+c7kjgHMFA*bC?B!L($@AedN#0U@!Pmf7ql zW`pX?Hajkq;ekx-bu>0tmJsXr+C}ynrU?eDG*v?{xQUW>caGQ}xWix@tsYyFcFIed zd7vEh^>(?&hA^+s-j4UsfDtC-_JRxvE+As-42RJx`BbfUaG_}e5fk-m5z7Rpv$>Lb z&9P!bGiVq=wiE0c;_(hE3$wW8*gQlSuZp`Ci3Q3yW!mY?BCOf-hi5X*?JP88t2Uy8 zdyDj0hCSi8PqG-F45bn%2n1_47@3t70~;K-Vv(u!CjFz+2)D^{4VIghz=<6hGIb(x zGft-BTRfd#wj31F$G=E7_EdB>V7!u_tF>*5U18yWTfAqGtdVBh)}^WN>h-ZSe@(bD zPYCz|5u+$Pvi!p_t_8L=jrO?Knq@2;BgG8Gh@sNe=kt@Y;iM>_VM8*ZP4FvZ0}Ua< z(WE;(Lc7MJJXBQpxV6KDmT1^TE*KqZstk`s0orh4PU%m{?Rp>N3VWPD?5dRZQKQr5 zK3llNzjAQkEwF^gHvLILEI(m}>pP0nw47A3E?4tyEJt-@FL;u; zotjJ3cU80z*0P%6F_7VjSR-+omRVsRhXS5pp#)~wV7c(Shb;?hG8rd`#lupBKBN7}Ms zqx}-sFj4f^`B-8SPjyOpG|rRh8>U^USt3lC)ELXu)n%%b7KlFg?%{0g%R7_YzoU^7 zHQCs{t{gern%>a#%(k6-SKcgVVfJZojDDe27;_yc(QCdnN=VJERP_cB%%N&cb&o*X z`(N6B zdZHe*P$|yD1m%hTuq$@{D#vP&W@*cq)XmnXBQxQ{LVar$2lv+8T$^phm z^31@GloHF^V$7jI6KJ02AE}>?n;8^1wuqaaz=c3dUPs=CCfBaa)Yd&m4D}k$bVlg; zWZCet&Y}T?VB5}&>L3*VwrWDZ^`7m@<1BbHrsm2FS=npA7c0 z7NU3+KCy~B3Ilnae&sX{i#62qJ2S@F&vJUnw6+!?>5TiUbk;<1#;PO+uB}UX9b2F@ zt7_MVFjo!iMkM5R4{`tmDXTO_m-c|$=}YT0f7E-KvUT2xdB_a_WDoEV)P2_ixL)D{Uo-BGYxcF^(jdZ!DtP=-SN(r=3Uv_^7cX{ba^Atjthz* zpfo=OMk@zDA+lQqKe;^7%W&68W5n7L-PfuOXtyPU5#qQG>f40bw&!(p%H9gf>T@|? ze*JQsciDu^y2GPl3S;M94q-V_WeuW8Mr=o6_bLL-gZ7OjTYje1z%j_UId~CVTud``w z{>Hh|bvnWzeNun6VWtGxILntwSN~;6e$jp0p%3bI4l5?Dp;_ z-Sa)WD{sQU9dI9Ps=(uL>T;RQ)zXH+8Cl3LoXm2j?%7?{JfI9+0Dh_|uQR{b9)z?K z{1}97T)g>gw#M0RHf@>M_YNx&m*G6GOhpn&3YvRt0!TMDMnb>ECM+f_Mg?zdg;5>9 zoP4>vi;tmI6w;2Q&c0r=7}-!wE=Kj3(LR=99{U|nxsFw__jY*>jap-$dC8psW!gt1 zPfRdlMi2Gqm{51C{hC_RPiqRR4DdA+wYDQ+Tnz%XaAsngns~UB|1wGZj}Ho455Ihb z#GG?=-T;iw=dxtP_W7tT45F{d60>z~7YEy~SH9pJV7|SckH>KR1hvF1_MR>{#yMT7 z+g4E1dha#X6~CBacDn-0+cK?x5WgenO2JRBXKkh5h3k=BW@<|)-pUy(FBNBH>-fW-tq8KR+8^<+JAo39)7k{*3iF*p)Pz`H*dcc4gw%kGDe&1y zI5-h^!S%ZNukxSC+$otj<&gu^snWg56?}D7aN^`roOa4D6hj5J6xm-jjzZSm(PSc7 zj4{{1iC}z-9H!@skX&`@$&4=744j`-z z#A$?TuNGaG;d@TN57_VeA_{%5H?c24Na+Ftr(KM6v(k5&6>*oBIG2c^JKZGZId=Xg zEjFkIQA84+PlG8F5V>&gmJU(Y6{9JN&ojEkCWl_wT4QE1P=APd;G@~1JC5F5k&{6e zN0&5K9Y22b$%iA$09>!<(V-kz!uauJ)rjk{KX^lv&J}l-7*$BS#+;;NQ=c?nI z{lo?$O&ufi8qo+F5EPho)7BOkv-f`>d}k}6XGi%&bbEmMIMoJch9J&(6sCe)T^*(z z^(B^<*bTr-PqqG;8Yf~QcU zX~9!(WRTQluXRU4ySprqS3>=Dr-=CS8Y?CtD3~2CtW_iN%{oc5Zyo)5SXH(-mhZMM zJ1^7^;Z8G~Cp7w+^!s9Twdt2S~@a3$IjqPJB!fiUQ?oF6go$8DNshC464 zIWzQJ)!gQGrfButX=p=7PA@!rCTzXXdK5H7R8(zC*TIvi@DcaU)1g84>P~0)O%%^6 z3Tw*pWd8KMJ{nKWgN&@UVZIM(bq(s+rwRl?)}-OCPD7AF!gmw4?FPeDiwk!gNQ;-% zX)vZP`LdFH^rwMCwIoNjMHzaH>x+#*tt2q0#?gob9FW(Ge$R7M@j`UV>I0vKZ*jW` zA(wl8=ZQ0sJ#JJ^pNfnXw$2z@PaCeehPq@)>vk5Y=OmqMd9wou9X&YGjr0!r385!E zfZn95=KPo;bfjPwnoM1{YnFd!SJ6j7fn&~{!qQwjl}N8abAYo$gJSW+8wAwW*ubb7 zu#xs-vxOWNvZcqM;EXj{5(oddQn!73JsGhLZM=eaG1?1s$+ZRBjE!3;rx84;NB88l zj71NaB#)6VdVH&=AG|D(4o{QQm=3-HG>ICeic`I(HyC@If@(K$y3gtrJ3Q?NQqly&Ma@JB{BV zKW*Ny|M8I+jl~OzT}Df4Ap+zNDEbbsr#~CWgh|O#hV^Fpf$(9$WfrMY-8PzP>(y(X zx3L5l0w@8YejbqaYauu?hWmG-htyN-W7mhYDO;KS++ACc#6Eea&RWbY2PrtZf`)yd z%5Y9MP1X%f4~G%R9oRb9!X(-FVtdX&z+%M^go#}MdTm6^=JuR6-b7X^i`Bf<@&*uB z>NEL}(eKVNcqA(Q%+=vJ;ibT{5iUy--fcQ$Z3a7k^4a zBsV^9UBOA8@8tM|hy|DJBA!RM%#e+mgyiXT6wlCTg_Oxi}GDwgJeB7lA9c17voEw;S!Izu=8d zaG9w>r)5BuH0KpuNbu^gSy2GmHjr6RNW9&80b8LyOcQ2mg{nR?%Y(5%Gv1C3ahNzE zD>b;IofPN*-UY2>H~=+pUetgsa$zCcj#xu1TzmzMdogOtdwp8H7exAjQxT439-US; z0Ri>THCA^*KV0s2XGNAT>r~a32!%b&_i<}>CS#VM^r9~)lWvQMlaVxdbTz9YivZ-Q zEDLrBujAwdG-TLHC#OU3yP?+@_d#gzr0mu~* z>POhM@2_6+MWCfMA0mZb^6BrDC^nAF;f4}SyMDeV>=G0-uQLsv^&$xw%;r{f=Jcs?`j^?Ga>;9laz z?%Pl)?EPX#hbN$kD3_NvC#15aL8D+vzX-2nSW0}PcdUD?<#zX@rv0Is99h+*)f(d7 zkOY|CzWtrfW^h);V;$;OXI z2R&ZcX;1BtZn{960Un-rhlsT4oSxdFQ{`3ovE;XiO4x3{$7xW;4@$Uls2f{65bQk{ z$*38cF{w`ujVl?Im*|^la8HkU*e{giGN}HDoFqX4%;-|LLe9DO&Ij6T-eJGS%cG>r zqO)!UI$qg*dS}oN8lyp(!CVSM#K)phg;^aG({mWiTyNTN;8#kxY?O$~QZ23s2a*`B zbT5&yB1(*T;X<%bJMve&kMhtAW>W!8XZJG}Zq zO1fLPp&;ni<@aZBWW?g|$v8Q(==LF2C8af4TCdIrt(;m-ooVYLE8-}5biYJKYcR-g zC!8GV=_|Frk3(~9=zyAlNj79{FpURQB)|p${gx=B`p4~xMnArd@< zb_Jg0n5ZxIG+;>btk+kaShf-#Ol`mB%z~LHo$(~?UKB=p@wsl;M2D=r$J@_+HAPV% zHZlEqquf-3VOl1)_nruA?~>0m?C9u;YxE+=nCK@ajRL5as&`Wpj&S!^)<&D#5OiCF zRO#%K2gq$i2D2f7=U^R}T5cV)#_jl*EQOEz$IHquiU)IS`+-3P?Zq+;l6qC`#rY+< z#KGp$BQRCHbkjm}@6Ikg^FJ@4M2Hlh#vCNYpm%{v(nVvhb~aKDJBY3XKM?Qw+yIW9 zkdBm}pNPu%sOGP(>|fsiaMy1DOGYcnXacs|HKB=;@t-y0k{!?TnmS2mr|gEd!=tAv z26~)qBVHT&bvxjg8t}RGB!^6S z=+(g+DeS&{fz2Z(3WrNxP=jt9tO>8AN$N_w)Lu>SW%`&h|94p6o7cR6V{cXU=SBn5`M!G2-B#Ip)lT*t(Eb zRf7NKe`8hR$is$+|lxJ4~da{qvt8}kd2me z%OML>-d9<3qJpryF!Z22tE-W*t5Hio#YX78iWpr#2+PTBO((&qaRt`M+!8@0J=jn9 zshWvL^w_KokNz2x@?3z}xZ_sd>ATF=@&3BuDsv^ns@0wOB8zCP8S@rg1dzrI;)2S6 zR=Z`xN%SN(@45*8H~X_YPo|Y}vQ6JVWT@>K=(-R4YQVw}w-KSL%t_HfJ=fFA5kkQX zfYCbL_niCKmg4ExI`Y=~a5a*pD1v31NSXp7Q=|Y@H;{e7@%ogA$q4d9of%bmi7&=W zsBrojkiSK+3*CFq!AHbH{&G+&OM%<9Dsx6tr6R-ITCUvq@RqqVdcEjMYVd97VnaL4Tyz`PS~X3r-&Sn6 zd=hE_()t^K$|JrdG@2$IT&+T-@RU*w=?kQkHWAy1hWIi#sq z!B=U>z>Gv;$qh|NEry;1=wIzmykWIDd)1n?(0DB~=YIqw($y?~!D9`a@nC^XD&MWC zQy-aoAzCHSq^LL?M~B*?HQ7%=f(#pg!T^=YbQlwgHdOMbum`pUZf@wlm7L$sYe0Uy zrJ~!i+Y99q-td=27Q!J@1?=P{Kw{hLyA~?Ub`OEb8Tglsb@%Q=g*NE|-_qWLL+w33Vfd z`OA!$?&pk{W^?P?4l*s}!%jH6XK_`F6qL+K7oPprEC^zRL*|6)d4aH=wH)#E&6X!M zJ-JiTa^^9zD?_A^T^I+oAp-Up`^5sz>{V@DM5Hccc+W5mp;<4WLJhnpi4Xy<*~0c+ zIVvc8(7bg(zDxySqj_(gr$btkbUv>mmU1gF%AiQgpwVF&JC2$tCk{|RA&#o?`1X)C zXwIu4FIqKkOGiOkV@z*7?NZtZO^Jl4^H=F zPZ}}l>lPo`d^x1{w!&xmZxNbbzD8)4|80ckJtC4jSeUEpShz%ZoVBc0)O`XGKvC>u zZ*uq>iI2}^-0E*5#y{Iy1UTyqhy&kcJYIkiOXDoAh5=?dg{lKoOe zu5W46Lj}2CAmaw`W??QMqjBfJUgF?2Z$G6B_H;u^iQpaI#y10L${yamGTFfQrD(i` z5+-^={w&1hSi%Iraod(uxowcRtmKipd@Ktpb=5R@u?$<--)U>elI#U$2 zobBpAOr`~EanaD~N!W$O*Jmu=a7jw_Mr$C~TAU^kL!x7AAL+ekw&V?4|7 z`dQ`^pHgUw(c5P{i^0&uTpewvLGh}tGChSl6A+O>P4Z$OzKrH318fiZ3)ELZ4CFzS zK4Srg*$5SAy%kOOrI-bw$s2Zd`(+D_tRJCH8wGj5_Hl30l8+7N$i;DXxNlcb8OdQE zU_aFJwfDm=zt18BtP}SXofP?Gt zEx25$g23K{qsHP^F6YC%jj_U&dm1O7agw6sH{Ir7{{Pz zXt)}B(+F}weeHR-+qq|e-h0MXO^q3>sKb*D_BFb=z6&$$W-}kOAPgXQrwJc%JD$cl zEfxhySVtK!Rf8^YDA}g_#jcgM(<;jDoMgdu;&9yeV<%t3%l~?Rbyq(^&Hpak{Ery) zA4gq&db95bSANvU!mn|SH%fVGkt(+9dmZzz-f5?HPcW+(v{Y1Vz32(r0fWKENUAFX z*X^x^Mn^Bmr{?um=NjAVwJ}5?1<5scAkdb0IoWCt1JJN zu+86+8PC%mx?Odty~{pO5&l%0CO*PEy_7NS@m5LtQ*m@@WS6hsnt;K`%)-BIA}urR zp4=2!mVf*gzV1gMMsQg%VqcbrA))s3S$K)aC`>z!4fNwOweENuDRV= z3*pbj0Cv9+pis2&e8z}^R+S!$0%rsxk}%7J>;O9@tsf;v7|XLqjtwK|4MSyO=xv=e z>4h(Mw4%So&?adr<6xAXU2feGW2ZlkBD@lr-!<#k#glgT8Pfaev)X3;@CxdOGU+5k+_I4q0$2~1*0w^ zFr!cgKp}{4WtWcqt||&0U-MXm&M3p5AYv3^GPZYATi;JZk*Rzw#b?9QbjKHlM&(U( zWUD`pGR`A$>3FvMb8CdiYOlqdDd8vp60 zZ?l$hOi`<%ekx<35Dz)A&YW7YL^@pQl2e@~SN`phmmia+Up&^gb1?V6yQi;Ht+=lv z_Ma27zca(H3zI)9d@cMfrtg;obK1B9F~JL}E9Yl701OC{5b2|9q9<2L*4L_W*_t2D z&RRPk_3GXLPUpM|pN#3>9v7t3mK})`NYGody!~p6Za8ZihH)$$lDv}X-7WgZHvnEr z|0_D8kEf6B%dW0bb-8w8S|26`e4!Nn{}ca5454%R^HVM8KR?xScOOLxsQ?K}O!vox zEotid`mG1qN9#vlS`VuQBOkqXl09l7ITvFPE>F1u_+7SNF|3evU)E3)ufH!>9W~C! zq|&b%5Z3Upj>*Y07Bm=ZRR}0gQQw<0QW<54r&fU!V|`!{&z*h^K(AC+2=tg!H5{aC zwD#|<_CA~1aZWy}O834_pwc8YpKJ5m@@N|N-YSk+;3&=Xi7-AqD4bnowFFQ1?>?_4 zOdC&aI3WFO;UzvtvJdlfp5r zN>=-@?Oz(E+vzJ3{@LNfuSG2WrD2XAUAd+Ctt+?PP5p$|zP_qh*jfe|Gl?=Hfs3K8daT(Qu;2a##NT}qHHnCYwv%N!kksYw zJ#&6T^?!i#rxE;%DgCKA-_`YBDgMgtm9HZFDv|Y{=IKuLLv{YJq~s&t|6;*$-|dL! zlE;dbltlpfgjNHbIBH9oX224+D3Q=gt;okvvanJ2Y?!vr8j1YLfawRm)x$I0nj$mGv z78$GBh~@;n&EVChl;T}pmMas}Cl2DU%XV;!n;{Y9wle18=mDT!4<_4Ukv@#ukMm;4 z6d7rp&GYu>;Hhu94N(DyiK)y(fp$o`AkZ5Nvc4SS_nU$ml_C~y^G~LiIi_G!K8Awe zDC>55GR;A2?=6-Ty5+bNqr6k;7j|%`-4@I--%^$m^ls6g!HZtVHj~4pJb||p#^My< z`1(3@yHxZ2ZRz$w3EWoik7GaRqXTbC`ieqtIOuWc-7NFi90YolNcYT_8jq3WQpLFx zS40n8+Na(ewGOT@haY+?F-E26zn7LG#eUQzj`TDhu*XGp?;e#94g2BU4&|u4l8*_T z0+7^CBy>z<7=bF5hDA`^RrYAPZA@9Cjf@`Mdb!-Q9+kIl$1y7mzDgnpFn6cCg4#04 zJYJM<_*|tQy6lhi_R6^DI7Ges`&`+vy+fL_TsrxHiVpuC9d9>~5x>UXi`+Lt zAK(2tyx?|aK*&m#&z;c1vT!{QQJ9)It|^#0LyBYP$y59|Z*8T88s8idBrPmHSylG} zF2#|vkZ1dsX4PDA#scG`)!0$}Dn-({i;&xaQ}d}KQhC8Zf6u_sHZhoOs$zceQ82!; z?)kGk%Q_E^cRa7_{qQH%s|@4#rWGJEJk7`9(JF)K)mbRw0CD6XODQF)2@*<}vmP$R zfwPFzxKx5AcvX2v=5 z{c8`h|Brv|VVqp-N8sQei=BTHIA}Gfa5Y-`sGD7EzbMT|B;Y0Oax$+ z&;gOi7i~Ei%&^HNX=!dduSS%og0lHdHWSF&mRQ)44-0$?tY3Jv!yy>gg6EKSD`PyM_LWux9V$ph!@y&L~<_byf8Q zG)*tWeUcYRA?FZ<3$2b)WWQ_~!pJbi@I@m45wlH1fcg$O>B2+1DH-V5IgVbYdf_eu zc;|>i8ZN@ST?iM}eJXlQEpQdh6GwtFokXv@a zCX$bf@|2O0!N>dT6?h`66evd=z)*G~Pbw$roLn+A3)0Ug!Bi}*6Jae%FB#l;BFv)l zwgj$;vkz6-Lj3}T)ahU9zTYZKO}NLri0OoEuEAk-35 zn$tGqvd3vJisnPvtVTWyIigIPb^Y^aB&tz4Z-YH28!YT=Ska%}u*yrpdQsC~()T1KY5>t<$^i3}M3 zPN99_p5E$YMa+NUN}M}CC1D#0H4q_in;elSE{;bjt0yF6+g!Y2C4NLJ8IZP~YiAC> zba(tw$eZs$uIIK(pX4&e52;dSY8T!Ypo`FnXezWO6>F79HB8>@+fJoixdkzi8N7U) za`%Dd*wEnq@R@VWk$;y06M%!&S!p7>Fny98Q3z>=+bqX zQ*VoSNC>4L6d0_1H4eQluff|hbHm}!tD+F;qT1+r-9)p$YNm{=FtD7f(78WO9xnH` z^{$q;kY2ZpQu#3?=Bz6HqL?k=X#ZXsvEBRCvCur~04Y2!g)E$W-1shQeV;Zn6?Tr!#GA>76u+5y zzI|izV7~9Mk@!5dYp>v(l>fZQkk{3`l|ENyy;q8Kr_g96Z24@wX@=Nm_%V%JJDa@! z%iQrA22QiW%m<1H3=r{iDZnB-qDqDH2aarn*6n!&A)XpFts4f{y9@pt!W(wwsdDk@ zt@^o*fwqMZaAYs`%PX^>ckE*?US168!c(m*jYD2w`e#H5Tg|K75=!HFj0Yyi*ZcRK z9QZ5VP3yg|#L2NKdwt?@KHaDhTctyKodoB*S$8bBuInpB>FfSnD0-dYbHIlmY&w!iSZMqflB zdEhRqElb7U_(=c)?e22V(wkCaHe!tlE=M%m#eU>AK(w8f)QbyPkxu0BIGx0Zezz>*-lvA9jY~f{WJ2DNkKE;}Y(|zf?vAgQ*7a7a9RvaT44=YN zTQ{~MzZg{i*xENqk9*5q;2Sj29AACVL#b=#+#SSGP{->AYFpBoD+z4YCt+M-3dG!} zW|wc>+14D?jx4!WdlA!SpelBRo25ueY)sCd@ziOK1DigLPYmsew11~cg|wa%{n*{2 zzcd#0U}s7q!7pN5IrE+v+Y2}j*xqO{W4(vjtPs>4A-Wo3*$xl|#{wZ9A|vf=ne^HG z$(hlrrArk1teD1@!?)8SWz5-l?@X3D+=dpeu=1+;7>227l*nvgc~MX22>6(5*z-QV zmQ_+kV^5mX0ZX&FUTPGiGAvQTE~4c9MahPmV}Zg~;;mmMEqhNBq%4syu#Rf;$2#op zOe?m!%v#fx*(Ks{3_@eE`I8DzHfaaH+3v5?RTdZQCqUVNyflJoJUyD75 zUS1}N<0pfN#Db!#WAifgWJAR2*()qDezR=rd%1a0dbEPU;*8zy9%y<8Di-n?+$qTC zB&U3ejU@ND|JE`=t~=qiStJlZE}Ue(x~n5LW2_<|e}asAY{`-Tc;9(ZoRY(?+(kTf z736d7S8AsauKhdZ_V_OQ$LGUawm$Tab3&5TElbMpt@WdWR<8t4M~t<*1dhEt+~*?# zP`vHzQs;hP4Ijw`MHV#K*=6I{7l%DXo;~yZ6G5Fgxz6&4Cn)37sOIQN_DJ&cC+I{r zt{9DFIToG?ZmTs;`Xq;FeA=ga*M;g^)#+g_$JOjLIx2x_q;u?!K{SCoAOG&W$$pz} z@a;C0e4g#?t0rnetEWeq^Np-o@|=Oc=@hA_ z9L=}FnV~qS1XX#6*OV7L(-h7i#jV3MF@GuOy`0K@K1v@H_Hn9c?{oyfclg zRBB_1G|V)axmYfYCS~2a^SZ`SbG@M7!Zi z!r-`?sQoc|ygtI`3kI87o1^hFU%CWLotOY8&S)PSm*9=!TgiV|({Wd#TjvLyDZ}TV zxd$Pi6*cd26qqiq#fAb4^+jfaz3pA3b{UU5y9Ac&Ex?G3v2D3xw8Eil2zYguf80hf ztAPZ+@hrM}8Vg7e?TIl>R%UX3N zRM9S@trC&I0W6oFqgCxGfqzK)`T4-4mopJmVreJ~oFZ*Ie5pPl=D6sjk-mr(d z{B?VqZ*%+)OR{^bD@=y$@x9s^DF21GCN0q}(Zu6?QU_$z*AcjS>|kuWept3p<)`vr zAGfv-4?^TGzI%-SHW|n3=_-L<2Jx5SwyU5DJjiy-o>rY#bo5lvnMqrWO0*dgB~*Gd zOteFdhbd%`60&MllGil+i7SfACfH^nTaSj^84m8m~V; zan#@uo6CeiB~kfY7-{RlDp{;-?0UtiqCdT~`Bic#^`$RmoL07hACn@m45@BPtnZ_t zpUexM|KFdU|L^aK|EgX;m<9kO|7nWLvN%=jc>6kiCr=Mft@*z=uNrXu|8ZV5PX2#T zkN$gAAn4lSzp4VZ|Dg(`fiEcCTRQd<4j<(Uqzpt5s$j26WoP?>GVD|t(1XQ8I=@;( zcUWPu<`XPYgt1E2sWtUpD;XYAeooeA2v@DVBI4+*{4~9N+UPnC`xDv0k|0^~InJ$V z(Dw<2N5;<^jV<5WGlq3a2n*=PU)bq=F=^WWDY9P9!K2; zBJg){r;Alu{Y zra?H1YYgphn;sq-edCKK{T#X*hM691WZZ15TgAh*TGxrG8-*R4$np_0lyNIP*1{sj zm6+?smjC!c-bll=Rb z4o-Es(VY&`KKwbT;S6s=C=-Oo>1ZiXHS+rR-&SLl_0w|}L1XwDWaCt;;a(+talb~W zlQ3%kN6*r;_RPw7mho)7h-};B)bz-=bl0W3m*SYRc_rofGGEJjAVNYQsc<&lEO6sS zs*`1be;moi(=eHrR2LwGGA|z9bT38rovJ^;B1E+yJDmbv5Q=PBjh-(dbir~tiN^4g ztw0T9lkaY;`%;}d@I^y%_ms?pmQlG1E8nZEbpnZoY6wnk(}>FTibMofjq+euqj33& zr^dZ+P32B+qvz%8G=r)jqEcG+7$)TnEvaLdI?Sa2w{P8mL;9L(DlYV;*2S^(DPRQ6 zR$4NlgTX|1ztYy?3oXwG1pk6>tH3462{Yy*GnGe&w1~O zxDhGK3rkPsw#rbIFRd8w(1JT-ev2~jwT~E=>ESMSZTk481E5?tPvlH1a z`YY?sIccLC;9NYMMoTbUKq9>(A|3(t>`^`L^~r~5mjhzcRL1pR;oW5(7u8YclF-I} za__Y|1twckM)OLM#B6vBxnv84aX|GmK=bK7stnXmL%$unkUa6vBz7$iKy1qLnUi|$kPz>t+@m0neF zoi?G$^2bIgse+f4$mgTuFvKXGH@=u*pP9u(lC$Y4navjp9Ts*4=ZSmvGjh2jsuG<6Sj>&a)Na;!!EhzvA^URgXjb(!12P=u)BKmZ zZ(<2Itztcb%jl^N_I$29>pjnzW;ycCcTGrn^ul`7Z5l~dQO*5IqZQKSxLBRVG%rB6 zYC&@hYy&6F+Q`_1WE`xdj;5}BWbG?hLpPZ~K#-3k9XWF)f|IhD>ovC1jEMHjPS=b0 z2cKejAqbSM&kFo&xtmaXFe(#~UFSlG2 zIX|-+Qi`+w?$8~1?rx^L{qo2mt2z}=39d~>+9@{@1_o}!5@uP5{>fZ?bGzE+TqutzX|Labd3471gLGKirqSrVdGN0%<~t(w$6-@D$|bE>Ik8z}?u zIvQVJ0#nvERSqv7`qk=M+4!Z{hV%NG$%vS9U1E_f=Ztn z3-sNm)*t#-FYgz^izA}Kz0J>FHq<8Qr$tSbHE?IYGAl`P2mK+hAu6xQIcR@r!E!j! z`4{|qa^=?*>#7uf7=uSPP>W&NWU-l90It)C^UdBhOy>4AxSnUy)@gN8;_C$AhE=XSuG7X`OB%by2g_ZXhz3nIsrRanO3HLuH9p(2bL* zR{W3nd-?#mvXNU{g!S8iZfR7vfh3FnMa&A5mtN?#CBGCK|4KsVLehTGO5##T_;m1# zobavc;NBE1GCpnR*)vNG-Lm1{ z=>5lm`It6tye;-GWM%J)<10;vM==q>$&34IZ>QMGh~+9KLnIX=hd%AzZPiQk2nM8C zWf$iLqMEaz22t~VZDXMYIWWf@gXA&$s3`OT5eUl(HH9%GGXcDI0_(niuIob&JmX@!WMEO;FPk`r%Q=%+~1tNA4!I5$cWa+b$2q#+Fy=9~OUU-oED?63h4a4=)Gz z|GJlhoAO)E#+GTFOYe%cPp%{Rxc<&7AW|jtqEan2YDa*ADz|=kP19i5P`yW)AhawUbbl~CufM{EVm!{hogzBnY< z?`0vGCjU0^_AJu_LkFKbd{y8_dE<0L3@Ajhm2{07LbUQ`=k8Ne`Og^GD}cX_hyCnS zO6{s6|Fh@K{62*WiVG-p2ida-?N+TK5?URJZ+Or=e?9K-Eh0X& z4d_s5Py(g&uQ>8|;Y`I{rh0ia-aOn4koB1~&m}A{2{f{{VC!7+q_Fk7KWJ&jBQoNb_A!46HnQDz0bZ z;>tE8rO2Prlj8`_^3S)2EhjdUlz&#q8f| zeP0`cr10)1#K%@PWl;$~_&#kA1Q&0O?FGuDhuMGGj2;c9;oMv>J2dmy{*^O&2=nVY zq`_zmy9zsQxS{{p+)pEOyEnUhT9XrY;?D{dKCBr5+-BbDH%j&Ox$}CpG*Ze*N-a98 zQOT<@12}ZM&P9$`_~eOl1|1*!NT*GUg4IFa=CzzfAYSc^NN^p!a<8}@f|ia6okqwa zk0AUSaP_=_Yp^;eOvdVBVOVszCmk9wFs`hM>0G(TEd`?Gtrb1Z?+4(s!(E;_Kbji0 z89Q-9STM3Cj$Rw@^jPSfWxevcodyMzV=^p$JH=$Dt52)=7D@{x`ajK-wlLMIw%-Xb zZX64#3@}|>4wa_1YrwMp1xfN)3RaOLo-oqhLX7dEr&HwUej}PkChMv8>)C-PGrH|w zmjmjL>s@P&ty@984Qkn28ho7oNh!!(ytV<9)I^)ZYmP&2 zG!hR{#S`r~Dhvs@6KH6sv5ozmF}KQ1;>hG(D@d24zFwXoEkKfNwSgqM1xRUEyt%?| zip?rTbEyQ;rs8k%Azb}zPS#8uzCHA`rn&dAnY+rWwy;o)f$`Sp()(us zxFuqWN=A;TzgK{LUk&@K8-p=5cBpP)=yxk>lI+nbkc|1ADZ6}}Zx?B6ubkD;`WpJ( zacOQ~Yh819UcNAJbv)$)tsbY2!M34|fk7EFsFr1`zm|`z4gxZQQ|;Ok4yGZ>VK>X# zF3c9KCjfXf-~Gfjb7fHYk5=7vvox>;6Q37XHdSechMN#_I)XbOJ;pS9fy4wiYX4Q( zym!R|E!+U5GgvP}ORDZ9rm+fL-TD?NK|BIxN8!sW%VbKExIbdB*=_@&2DLt9F5UiRw3I57r>-|#C-KC|qgTeq<*@$3_^ zpRi{uf6I?W^ps+sS3A$thZZx6gs2tJNK$`ULm7y^27DD-(jrp5N;hMS=m`F*5_{{s z==m$Qk=)k*Eo`*hmC6H@o7AQc0EV)(&}z1(q^vInFsSL+>D%j)WRCte8+Ez#_Le4- zA#vhX%T>oZ?3XQda;Tym*qD8yd}(E1#fiKH=iNQeXXtqiH84Z1U@Y?K&;XRPthKopmTgn zs18cp_3&l=8>HbMnIlRNh)S>C%je5wYrETSn^09?TQluSK`R$ya~CW~AICkVpHvrf zjVYC?unWtbcmrT&3EBB5SyfeQ#n48)TpZG6SRK1Di1L_a^M<$A;cUvi51kO0+^|0G z-_;bNUjHO`aVube@NeLxY~OZUAnsFJrQ;{9v^3ksv*>ScI$f%>lq12Qw=ig-& zWp`9CxQEW$Tm7y$!($H@n%8#RsKe(#dpToeFRyHd07pif({FE?UnY8a#C%-=T<7}s zV7G_0<9LBAU2Ul~Xjz;(eHD^~SZ7~$g%CT|OOEh1Tcft2O_HZl+Vy^f%( zu(syv-D3dQm`W^#(s=Pbwz4V>KBZB`0?q!#%GUtZ6xW8>G3mq*)>K2Cak&Vt_Fx(T zfp$rPIk&3nM_)uL#UmQ+|Cu9&t%N`5-a5Zmb7vEwCe~tsxM6vUoVPM0_9)Pm=x=) z=fb9we!|ghStRwfgdN_P>-;&vln-eAA~4vD`dxR>!Y5b3H?kHMZytnkhg#C|A6{FX zru_sb5OwDwMO)kZ;oz9BpBi_af>XY)nkFyGqCEAzPvi7b-mS_}1<}a*Q_i0kt~v2= zFk8!szhGB%S#vTui!)NvdGdbnfbO-6M;yP6BBb@!)2)HeRX*C0F`BGKA8iJ@Ou4`P z^b}px!0c62&^$WHphwT`?gFhCd{SZxa;lBgE$DocNPxjNZOt@mzn=|u_8*<}`%ti_ zwy&w{Rf}@&>ZFmUqnr^)N_l8`CA7>p%aU3_$UWa{6~r)s}+i<1!dB=mYD(D>56BA01w4z{ROfR3{)wqSYy77>GrK zMO`w|sDz)sVL3MRWWJO0`Hys369`wXT7OWEUP7hc5tgh64VmggNpA#0IWBr8tO9({ z#VDIWbRB;pnNYoPUhDfHBEp;%NR=6*H#axrU;UVL9{=y;?finBPaYCkIGkGBglQ$PJMEI|^y z*}X}&X)XAHHm$>av#>h$wMD=Wx{xPgsY)~k7+>eB4MfoAk$nfGqhIZABos z5yIbQ-@x^E)>8LHPS|=ED4KwzPjG4SO$OyuP`tf_`}^Tgbib%ps)5wm$+eTA!?T;7 zZrHt~owwSPXKiiC#+59=84<{rswl(uaK0UtJm3>E{dYi|+y*AMyHB&X0vDv@H;?Au&6+y#9oL~%!&be?vsgXLv}|AKBT6Ki10 z!g?F2=80xL1wWY}a)9*dqgrfbxh$ebLWRLh_kh!S)1iJrJGgJ8^3mi|H`o8xe{`zAk;gV+yhM24?oDYthe$qmOn!{ zJCg-=haUTt>^vBLJb>%dv>)XH(fWDdMFWY zt(&LAm?Bo8rJ#ULxp_#1#(3?CAtU%}r-G=c5%#H^_M-lyO)Gs>R4UM-sKc?lL#JmY z!|PAo#StZp!8%{_y#RDi(2wsXiU*5V>BkS}m8UdvEELJX3Z#HV$eU)@<%mZP(VNlL zADa3)KYa9>b3;OFT7?TWO02#|eS!;J`+T&2)28>Eoa1a!C$djNrdi(YZoQHLPxw6! zto(f`dyfGyYZ#|!5->h^dl>}}!~70sYVF!RAq)D4^{$X$v8hHChO6(5iqE&XTD6Ly z-3a=Q4{ro9-Z!4<85Bei-yFkit9bo9XCg^mTULeiP2a&F-j?^FI-1qo^>P4-;Lxor zW1uGL-l{@k?XdErKQ9ZG)4O4Dy=TkLA$Gd~fVLt%1R|Ryyv;X=(2$7N-i|D}qn6#1 z*H1?JE2;j^Gs@Ap)?{~kmIsrVA45w2Kx~b6NiW*|`VZMotBcO*@|#Rx3xr#js(`FS zCay^pS@ha`DaUWQJ=ash#b>x0B*FX@i7wj7PtEDFq=#A+KPO8y2 zEDgI{JeyrXN6)`i+I^2TiYkk!Se$dDzl?J%PIMuFtcB2us;`)i7}VKx^7XUM1aS_( zW{d>{>6l)@b)l(>9YSN~xR9j7{lehnvX(=b-k zsdKU5s1645PYUp;hyF>=Vkb9`F=>}JRl_2zlV^Jw0AQrX;MUw6lHXFiDWiJEIfP05 z{jrzL0X$hF9JIV`Ydr>b-s9rDdFQg5-DI)sl;j+Ygs^zT)mXER%wRBbe>hc5=4WmUJBw5jO)II^~0+LehYs#dQtG=u5ZI@uB5MDLTf1)6?w3S0QQ zRTADO4!TTOhkz~b)7RnPYR0HwSvO+Lpe@OwII19t0-6E?J_@~BvL6N<<$tjI{ukF^ zK?EDo8HFu(ax$rmkq`%q_dhmbI^GZ!-Fy5d=M-ItKsoMt?i~FfH@(5bn9Aw0l*{q+ z?_VPdyiXTv=5ID$$`;!%em`ILjrR4~82R-?s#ZQZbU`@-ZLhvbPlWVIaZTA*D30lz^I0=~h*&=P~BxnIdQA$3Vwj(;Ef!qj{PhEDwUO*mG2X>jMob z`Fsn2gIQ_kHxMKYTSz74vz5t4xHdjU1bECceIp;^*WPkGftk_l%)eXN=HNJ)7Y;? zjMc;=hNHyAS~7Wf783BLuViz5{W?t3H7WG+EN%dE)O-WI`C~A2@?_~nuZ~ZKLuI8u zn}~=qfotemQx2VWwrfOYpa2PGfaf+yhc_uUsib$pp!mZ5UW2)XiS|A zpcdC-w?CwcCl8Vka;_rHNrTs&aou1&TLl_MxNkN`8?0;LrzCC!Fa8R5$3Fb4JAXT3 z;PU{xjD;_|iQiZ-qTd{aYryfbTS%U8-E+I&>r9_q&Z1XyUia^-n~k?v__V6kl82Q0 zPuWH$7h#qafc4y9(k}eag<+v$gs<79MipFh2@6~D<>9wII}hevakEx3%q@Xau-Uba z#Njvnihx5ypUmC&3^$3=K1WwlQ@y6~&yQzqhj^xj$i@B!KMPdR9U4Q?8=9~ zhBD-=>`ucUEiTWIYA>!}d4$_@_9Ii_*MAI&*tV7KD?_g?o(j@a73k_rh$U$U$FJi% zu}V7?%+g@fY*vN{@PO!^(}WV?@UW(Qaq@u-0GKxW$>sj%I!eQS_jKVG0&h*>O z=Me{Cu3Krjfsm$VEc7LXFjHT)u@y@OMDiFT@ z@@Mcrtm4dU{YMzm+YLCsBZg1pN&M0&p_|LRUV3NZCHY;DBP1;J7hmm}pFC9H9p4Fl z2VUd`7aOt0OC^UF9Akr}n;!`z`!;_nF$Uik{}4hN+@1S;3~XM;{J513$i9ScZgvgT z)HX-kTK%$*G$Mf#eD}osF|_S}&D!z1LX>9bTlD6{*aPPV6?6Ww{JO1KZkmqn>p3dE zHs{>V&)Bd7a~-;~d~|eX_ev@I6j%Rk2abH2GHW+`%EV*hG^Uo~pw*GJ@F*gM&a`bC z{>7MecxGzAY27!E{rZr`96$7=8a|B=;!&M55b|vJu>%8Ezs+Hs2K^*cED_cYc0VcAVE(A*fyfMz48` zVy-eX;6F!|wHzMHdsi2F)UEqy`AG&5EI zD&_9v3Ey=qOP$c7z$a{}QByi2OD;bN6qbCx8Xg)uJIA;?;~8k{wQem_Y6AezBMiX! z(kWt?e=cemi|BMIIp`k25_FAp{laTEL%Y+TpTJ;HTDudG?j{aVX%L=%ON4_yS`ye< zqCEbA{j20{PsX-p*U9&nVJ{TOU5#s+8~B8RY!)}aT)YfV1&7<{YP2K-KR?AhQj+mY_bQyiwK4&b_%@@g-X1HMUA>&rHM#yDvam)doU!dbSZzUh6qEm-64UI5A z#6H0)F~V`4_IP0S^}e?6+q3{-aZU;;89kDPW;|Sx#-3p`7RpZqgn1p!c-KGFwtRhh zQ0MEEB?P?mcD1Oym%(!RJuai8Zc0bi?np!b6rtk~8KElip-a;;FRY&3P98`^`sD%# zaGf+-w}j|I^lccUN!*l{pQQbKjg>9ySzXZ?3|(1jaxbty2UoX~KV57y#*C^wsyE9} zp!|qt=S!>0CQPkJr;FD!pOedkq5`D(r&aj;1YA0r*yN~F*}fe(RneAwkMkR*Qz(z9 z0b(m~^8BJ^qx!vR*u6XN+<2Vbs7q0?>{uNQA?Twb^xB@wO$eHKMbPGdW)7go54a<2 z%yHS8zDM7X^ysT{q`@(%?ki%!vV@KE$x|&>u%mRCLK$nf0?vzogSc1ChCzfX@ngoTXf) z-I-R8#;}3K;m40S!w}va_O};L7Z;Rc@xeWSayUKDv4&Lx1A69Q6<<#Oh0 zpj)Y1(uNJhBGHn3WVGty?AJ-a_o}6#nmv)5FqTSE!+6i?hokq#^LXF{>wy6hJ*u=6 zd0Z?PbY01hx+653^Qy%aw?NvQgt2~2=EziArTiYS`s6NpM0*AasTaggXl5)j)pOFR zLk85hQDTW>g{tjicjO8eWix~9it1NJS+VF45mM%R>E%uP4@bmuY(kh;ZI)T0i*t=P zZJP)}eEGy17VV~B0!?p5gmJ4;1j)xKy=}RP{?k`E4<%THc_xUAeVkVKo&|2GUGtGzTf;Y>FqBGa zRFf}wjpo~x_X3VL%)cL?SvAIC{`2t02+9+eloS{ok%1C;MAyBNW#iuhS9C-+eZ^i% zmJ4?eO|bm6%1qIO?gOKuhq@0REgEe18#X-3gE%5EatR7f7CD ztA?-V%1tM3B?K%T(aX$~M1pbw&uNKsjVBC%!Q=Qwn}XuoaQFni$Lz$gY-p!Ln{egZ zL!mEEWyR+(rS45#OtML>X1dVMo%sv^E8aN9i?D0+$U=yq6sONvHja8rVHa(a3# z=i;-nBoY_+@~c}1ybZ=V&>ywTV?XFSh@&+wjp-sdDJ z72o{eb8ln*-m3w?cIf~JYlNz5esTVpFEV9pkHx0>HG6Q~KgY;9!Z~apz|~)#+1TU!sM{84c$&IQf-v+q!!mUJZtJ} zn&ot4z22vQtl85upVG*fT1YUwuPd!Ah{I*Tt28#E%F^uSA&WTsl7{WLRx$LakNhmN z?C%3V_Ey<*-PY}Nt# zi?wG?M+Wf37opFN28e9FOEsW6)goAB_rTII9t~D@P&p7s6MpQYj*XJcl z%dDQ6#tPIC1yes9H%h8PXAlw(sXEMS)m4R-iw_fTJv|8G!2hA+GzGCA?JRbx73zkA z054P%nTJ_shs>QDJ8kCEIu`9IiW)VQFhBFw-#@>-icNQAUU@URqNehsCkum;G-DCq zF-`IsnV8a3_OxlL2Z8!3-Pr1bgE+w2*d@Vrdr)k15yJ?^#|K4UQ~bN8X2maYjoEC3KDr<4OOx_~T{~i!s68(Rcyl8!&=COQV=}tb|r}YnuY3JimQ{?Pe z$v-TOFK@Xm9+H!Lu37i;f6mT7U)U)AfuoP?0&_mpGra$%u=Ewxoc?-%WMu+;r@Ocj z2<(Vh%v>T(dA7;CGS)jGa%^v2QOSShzWK#ctVzn3Y@gS?gL95T!l6#dYj(HEnpII| zNOYIEH^Fn!&Dl%VQ-p3L*kdZ}V2Z(gvqPk!<;iM|LXmBVcz4q?V;>Fm6?B$Yt=D?X zO5QbX4`UbUzI8)ng2bV@&!#{?k?dY)RaBVOvT4>iJOvQQfgGQe8?q7&?mUA+yV}jz zGR~XUrw|#CKhObS@td;o8*iyfXxs5~!#>ibr#I$BO>(wl0S`rDIo&e9gO4na+7i7~ zQ?u7_BqhxDLFShsSQK6xn?)aNBlj;QPfWjZA7(~+2Ff#bYhBhYTsb9{<#=4pde&4YAs{^r{SrOUUPi}CgJ77%rq2|LZ zo;DT6F|*&dL_&z&;cadM?V=5sq-ecJEmF(A74Oo%h#2lV*%+{fcNAUEbn(abpTKjc z3;*hh#*4|ho&C#M@1AC_{k(wA?(F)P23?To9KXA&*Qtz|RgwaypCR|$>?~Z?B22N! z1m-hWsUG}T4OVBjNTvy|XsaVf3b|mT+78+|bL-kQCiQep+@TOnIpl8}_nE$9zfd)h zvtw0auF0MAvZm2;PrMQRI6KR1Eg=7cU;ve3D$s4zGp%UNw8Xq2PQcUhXD(whr-&JdYsmjA$X^U-0C1$P}Y9r_g z=14okFL;qjz$6=bN#c6oN&BqbH!xPP6@fgBB+miFG`Q|rj`OPOlBx4aPIuq; zFa8WK0%DJ?;-;OrWulFOd22&7eM8+JbXEYKqS zpy>ePWWTr6LE}^UdN#iW>E1$YLBs?ZiNG+mgNMSNE8xcMiT!-tUI+~kk+)m9{?WR= zjBawp0wg3Zn%I1~ahrZ`)l$FX{I&BwRe zBe|t3intZZyDY7-x|7F|pSJYA-_E5NZK>A^IX?5e!rDpQ4bbz6U zx9|*;WR=hZ6V7HG5U$fRW-yhecimLGm}69fjPLnm4a09$Q*7U$Y-?~Qn0-8hF#vKx z|CHNdLCsn({psp`8*@IGe7@OOfrsm|7K4uTyn`(#hy{Z~8ugK9&TCqT)u1~crr4dI z>eAJKpLO!T%qzlICDy7`KDQj1D|ei>mDky-_jE=JyNM{CokCF0Lwr80`hc2Nx}VaH zd1tfFP8paYHtq=SB^DHDe2Olcy!6;)62FIf4AXv9LX?)4wDA>62EJm}EBat>{G*;@ zI?Tg?Ntf8yOzGJ&adKn*DIN=d0zRfe`IWuy~b`}sD?P=Jy2hjMz=V}RWQ=`wWdI76Co<$ zY-4+KJJF^v2)*fWLZ}a5&!7iWn+Znb+!meBzY-$TXn4zwnmT_-t96YrvGip zI&stc{WjRP@D(+{Ke?847&*Tezq33FEUNF6T$o?59hd+GEQjYmty> z(1Ov3(HMjJ3#mm^WzdO{1?aI6zaEI@JnTiE0=GQ+ z+r`f*)K%`JU6P0A#yH5+)5{F%m)J8?Nc@u~c{83@$3!u4=b@}7Nv|yL_RJ5Rr@k*Oz0Cav&=%8v30Woa z%hD2ZDJCvRkdAOG|HJ*7%Sd;LKdCfQvtoMhd()4|u|RlVuZx1d!FdH#;0p@xbkTod z6t{)C#tl#BWr}U;==mF8{&bfurjj(iO>>M0{SPFTkn}kOVBBT=(I-yV=n8m38*T?c zZx<1fwb&2mCp%qE?YKEyi=5rm3v#|>kNKV&w?zH$ZGP=Bl89lh@r_JMqicr7tD7Vh z5}9WT=6FkrA^50u#XHxWJjm_MK&+f(SxC7DG5 zYso!*)l_K5*Ps{P0qf@15eqUVD)Zkrby_8|KA7xqhjPK1(K23?|% z3$O7rJ!19(WX}Fkv-EpMca-??c=a!0nvJHMx-}RHRl{IQVtsdGWXG8qhvchmru6-G zlg~nV7N|v==bxQ@boP9@bJ{w#(TIAM!c4ObHl<<9FsaC`!e5~$R{KcX7fS&BAUB z)-0>H4chpgVJV|3!3RXYy5L|cZYxX^4d`aRA*YWV73i}3&FZtcZYqXWG6l8j)};m! z>(tI?6|*RviU;vj9AOF~xN-;)6{f?PC_din>bl9ka7e_2RO^LjddVST`S!ZD7q|0E5S`O;HBLpx#8d1 z*U_Fh3*(-n-}j{MP?(>yB5y^}}!a_qWggbQTc{hOGV7 zt(F82`Jl%<(;gX_{xnVBl-I2plZ}Hdm$OmSq7s@^G+#V50O@GzIWl(oslb$}_<(h3 z5e$T-Z+<#&gYPeU^oj}$I@Z%2`A->R1C-}(ZlW1%0O7j zn)auxm1|cxE~Ebq&*MEr^z$~o@jonrkcTqkkBnEavHyZ`?Rk6q5&3zrc;~kwl1h12 zA+%$i-!>mE`qPE*&(fkOZwH%^^7olSf%O02$xxMkY*;7%6bc{DzH2wN@@KrV^mi9B z*)^kR?cEA`q>)CVABD?Uw3s)l`&=JZM^cQJQc9y^Lga9PnJAu;i=x_iS^DmV0H7%5 zMRHtl5BFW%xTc0ki}bAfB#+oFRWg}~3g?j%$JRgQ=UjUHKZtwprzYMwY!^g8dIv#4 zqzR!YU8?jB(vkq7NhcvekbrCUKP@TA=LKVf$K!CBl(StSeED zBLm;_O_y_{lm{t!rkXIy@DvvrDmPP?!6xaq-Ri7bshv3LTDzFy5F`As>A)eDW8&7( zKW6MU8H@G5j>U{Ao*cLRzc=^V(La1P^$r)z_Fp|Gs@Cw@x)vK%0tw39aJK6Yv^b#| z;`h#hRvHx*VVc`mV~$5YFFK_gonmvr$q%^6OCOheH8U%He5fL^wTXu;tVlpm3=Y1o zG6kGj=t3|E{|UA9+iLCXeW1_ijx(|XtjBkM5Va)!^r5gM4(&qT2_~$nIB4u0TE!t6 zhDsDRpWNHaNc2{fSUlbign%LAitd#DPU%-bFRynJ-|afxd7&`9SJPe<#0C`FMk>GF zntecCcVdok2FV&Pk^b?9)i2A^8VBk5a2L}F>;g{2r2zpGvk<+STRd2nWRNQ(zpRyY&H%2@Bf?u>Z(zoWJe8 z6K{tFe@?casw^DxXN(f}d7fxoRY2uyFXzhhy=VVQjGF*wbrGDp#f*RAbeM8K>|4RD z-?wcQ8HyZxl!gXjry`r&JpR;cic=Dx=G~SV?kMiM0lj)>9xe1(+=!K}YZEZIgWr`C zo-)OEOvv}AWk>tyfXGe*1>1m&9v$NJ3M~t#aN6wI^}T;<_^bxuF~2HIGbwY?*a}x* z^!{EU@q4`rtr6J_3st_dM1f+aEVG#A*Y@4ooP?jRLRnWq)gQ_H>reh8OJYg6m!`GZ zpnPGN^fP8Klw((A6sasxv)<+2h2QOSb@W^>x1|_<@gJE=63lu&ono^PINs3C7>JHg z9wkWq)PKof71g+S0hiXB&5;yC?O#>VxmbyXtEpUJjZAA0(yOiB^PQhL^&T0>G)@O8wIu?3(p2)EY4MKiH z59uy;;)}ar9@;JMz5M-j*=IAV#_XasojItuxwDSA{J9D9&Sz%&JXeh0uzObV+wm!+ zV}IgUV~O(h8RU0JjY%~W&Cf5afd_wAU&Q#=CFOUI>hri-eHnUkX9Z$!&yG{ZTkEG% z2R{@U^}bbmlU480pzOO(wRdP#v~IcI9k8YD%3ZL%)9_t<{f1LHGOwPh55`Sh?rttLJrb2a|SB%=Yds`y|nkC1sqq zW9M1|v-L|H6<8aaM1`{lAQ_(qWpGS(D;FwF;uB>Ds_kvX{|;D2bpoV$dica>K{Yk? z*f{2NzZ$FcL5&#pVPKL}ZGXuF1!U!zZ;Z7fIzmJhVtEFK#o06@~}Ou4e1VsXS_AdH)FB<{#;t;)WKsvBeYw)-@Brg z$2k5;T%G5|R9Ir)e)Zk{=?VlJI7I2BaJglMIl6wuWmA5m?T*$5>q)zM7L5X{JH1;s zkGq#j5uYJlw2N>x{02(R9QgM<$u!t=bn0XYa<@}Wi>CFtyUGidUXN9mxebl8y5Asa zQL5RbnbD9NO~0($0g>gpmRgUNyw+~(9G(JbMj5>o)kS73>Csx(bl{ev;-166cB4${ytpWb z75J&;Torz?t9=h0JFGBg-u!FgHsYTE!XeKk^Tco4)Vpp)ews_gg~PO|PhfK@r03yt?J{P?SbP6+j=28i;_t<>YGV{qsbYa9$yN$1aS>jflE7&!* zwsSmVxby6e%Eu`kdWHm-`67ebE3?FIHv~Z?la)?dV=*b zSC_Pej}La1nys1~TO3%?WYZ5C`x^jvo2jd<4%#fk^H}A_3Dn5SEs5melYE5Hy~@s+ z>`8i-FNGlW8P=1ZK!EKCZInM1h<4NM47R$Q`~%~E!43=yqGfdWVzeC^;%=YcZTi;d zNNfC6jNFU;*DQP2M zsykkVHN?=Bi8RVEhhD;-wW>0Vxj=_wDXXn>iwTcPS-9m+5{ge*F;Clkw91+hPCyFb zffM=2$)A44pihQe=$l9KrIwW3U>m=rZ0XuPsEs_9u(S2Ob25kSY;*>E#cJGf7B`hl#kTp@PB{1+ zW`r(%bYaNJ(9S^Zn2*iv5YKoLgAmsFr12k{)t7DbDvL`G$Dtd@E`rp8Y#U zUzaiIxtM#b0xpS|wC>$1VSK?ee**_N_?z+`YCWo{vB;heS`%xNK*P$UPtjHRgn)_5 z-W}O9_*|6s4ie5nb2#HDQ~m169R)4`D5J|{X_cZo*a9ur)(GM8hA-7N)yv+so}%ZXf}8aZ6POq6)!2ZlMDYUCl!3ko$t;yUW?b@VfJPZZR{*R#(T< zL^R?@eUh`+Wjl_gDQ!-f1;PHDR^UduD7SWih=oERVWDvqAuE~7GbAk zHn-zFwY@Emh$yeR!hsQ+`|2EjtX?)so6Z#?dMq(FvnWzif@Oz=8w+j&{P9<9ltx2r zBagjoVcp?^V`4OoW-C00skUo6-UcYz3SLh&cTDES=C`0X)O7S$OJ%;7qF=UCVuvpsWG4YcCH*np)uV za(R*0k!21S`8Ke?UnhFhCG8^WR0xr>+J9IIuc>l%ea*E_+w(1-=MW$XK&vOYkE~#ylm6y{nEA&VkM=7hdKNW z-2zNPX^-HV5-ZCDesVZl-0-gfwa~SN>Er~Hm=oi7R0c^&cPr9hV1v?ZQ4ue(=cXR1oLfe`HRHu3A|@HizR78U=FcTlub) z8Z9?<)=;Z$EQe4srnx9?d1M zgap|pelG&|;i4QId`s{L(9G7xW5A&h^Zi1_Kf>Z4#O(;D zOiU&^uyIUF5IPhD0UeOB7xee;q=ytBKS%Z%1t@1>v3|(yZ6sHnFG#FB9A{RbBDnHp z=*}MHpo>U#-6qW5tL``7Z}-rr$s27|r1^bUv^{ce8e{w+h|i@^BgfgI3{g?2tLqy2 ztwI~0sRXHU8&8F-4{D3Z7uEzq-{+t*+&!jkUVU>XYxs&!5LKjyB_U9^bfMY!;1?3} zA7$zvQCs#%eldwZ+pF3dK6)3iU?ZJ$a=_S2@#u9P>%Zsoz)8JBs$I=4a6RH1d=^)T z&)4glPsA*+CLn?Y=*7`U?InhaIn>+qgTk6oPR$|cVqJ+qTxO(W;lJNjul4;iXrlwS zcE7D?NcQ||DJZxT8u@9>E`Y;m;jc_=>F4`&aec>PKPhvF8XIeAdO{7vc#aBt%a6Be z3+?*Z9X4C{h#O7{m!8~>vjL@7e~1 zlD9klCdix${|W0JWw@b>bFDGdNldS$OxC}rC{CSK&Acbx=AXvmZK6VMVxKu&h2w9F3(VZ& zfOhTfe)k z{?p@Xet6<`ut)R~QGRt!;99Q9S~Xxj>!4wd-EP77n(|!PEhHsEVWs z-BfQ{$X2srCWwj86x?~%HhYQHYEyyJj>W!w!||}nn!`H?HE(Z4nCi|ueH5*L*KQ%CE)y- zAW)a==a`x$lSeh%5P8`yW=pZ!RYk)^+%hI+^W`cRlS0MA_dgq+@{ATO4iAkR-Qiwg zYpdigx`SuxvaC%n80>esnH*r*#-8uJ7eY6;O+u>R$Rj+uvla)L4Yong3+lkiK`1 z&C`Y~ULncwW0(Tqh6`k}x18q1xx}MWi9M%hLa2%Z>Y7uQ;=M!$ez$f6^S zrj!}Lt^$c473M-#F=~2E!GzF&1S?~Zt!erIciq0|(t{!}KRxQ_x@%=(eLkGst1O-c zNDKe?lGpdkAn7J_((ImNU-5-C^b!u=x7iy$a}#cph|XO$CR7yi(bXly_|;3dR_4v< ziCefe*#qi1mjP!YK+Tc>atqx+@AfAr!7~!fai&G)*8mlyb5mN$~5dr|95Z?Fr7hf2?c_uqkaSUUvSzWGoGFTeh$ z-Fp9gS^4nOzC7{yA%lh&O%-up{alf`0yJ_Etrxf21uOUxb@G97NYh9q%H8Yx@o#a5 z)&!hv2C2EQ{YVO7)C!52*?S;9*GU5#aBY6W<=Mnv4!m=_Y$YI#((JWyZ2$0G1rhm7 zW%v1&LO@J<$h*(*K_bWAGe_a9X!PEj7ftVI_c81Y4XzJ9w)&z!13lG{F{3J+n1LGM z@mRV|!nh;GoYx|X!(q~daN>xPe`7!WIlIt&1&4j~NAuqV($o#xvJcIybo|=x_(ixO z-D`0AsW66e6wi2xeF+29V01+XH6(?|g~FrezQfWG-qs37;Msl!Sq7Mj_(n~`=%k^= z)Q$&TefPc5>AcmJu!)nG+sC#k9{Yt3O7=Onav&A-I1JEfUf(zH3SR3t$giGIv)2S` z=)CB*UQ`G`2f#DPJ46(#8Za<#n+Zxm+&-Qt_tKIBt(frRZuAT-Z7pSk%YBZ70-p;x zvyUF7;|1j^Y~^_a$2&h6xLT1sJ-&eD0_8Bu_UfMRuO-!*k_# zA!mH<(eO6paOvG(Lw+wKo|sv(L+E*`FYuvc^0Zmw&E)kTj10mmcqcZjy5nWwKL}{R z=l13IrLK#K`{IT$SW+Wl#T)(ZTiTwPgYGaUG2HH8lz;PQsrZYLiYX0B|H^!E?@6;m z5hor~C8v1V$Ypu+E?Te0Zk@c@pr5cQ(`=n$4s7QkKuvqaIiLA{-Zt9q!mIkrV%Dm)b_`;XW1!JH*4>{pV z?X(-{&goToSMjZg!bschNDLk7Pg9Yh9Pm3ZSBBi_(x7k2 zX40CC)ACZk3aFz??_1AljI(q*2B7nFW2&12F>a4SLD=5r+bX>G0uL4&zj{^tm=1){ z?zPNu+L3OfkhX(gzrHiNOa|WOpbgxqI1~^x+dE?rDj()cJo+U~URJ*PcCEJg`V3o8lgKS-U%q7&vnLwUI!^1D$5 zS&9sQrDvJ;A25>?M)6k}DL%*ohOo-Wp)zm;Qjt!Wo#=f#Sq@sm?Oq0cy?C?2GNCZ} z`N&8bTO{L@1>3QxHoLNYHA7r(R?7+GgKBrehB2ZZ?|ib`bi-m0^_8_^N2!=60rhxr z&VBanMk?vn^z7Q5sok#ua|o*~sd969wlBP{<&G+$Lm{#Uj~y3}5Fdw^=H|tMBnxbe ztF61ChB-mUr!*3{Y~T%o0vhZ!FCnqm5-&bfX>HJ~TP7@;=5UWS*VK$RU_4thrC|~)k@MK@ovsKA?o@4Z65s8prGF5|+f4$!hMfX{k$I&|YA^ck0#}IL-(TRqg z3X>>f^88Ak49_n&Q38u1e`z^{W?69~#%rIf5@JhJ)|V+bY$ ziG*~C`xt>9HB|KnC2k=U|Cax$5>HL-i-(Ul19`o50Qhij-4Gwk3JNU*R(@c~u`_o4 z2d6@IwI$uVY+}`EQvTejsT({Y*v!evaLzkcP?bKVJy1twbZ&Om5F=4bFeHl6;my9u zu>K3w70jOaE-lt^`rPCBnT1h9QiI|{Jz%sS=BApBA>8Z=`LIh-;j0rk0M<+O)Xtia*otJc5fi- zFx7rlIZVuWxAk}_kjLCdsB|h*B?RsNsqqbpQnW){w=kSe!>}*&@MZ1!ROqp|-&s)k zjn6n@yZp=GfJIm&xm|)6jk6rMzK8I<+;+G}_wf$m*0c9uis6SY>6T|ct_~VIm^B@| z7AJiWfMiiQ^}UggMEk2@tQHxVAD5ooxZq`(nH2i8y!;Uh)7|}8>TE;6M2ND|`uK7& zAJpc6;FD%Tzl`0D6+(u*fY}{&^#I1dHtO0JGy8vKx8o#Df8O1Uk59cjB^1>W(wgeIF1(>^XZ|yGN`G-~ zW%_Il*~wf~v;I^28}rh@M}4X?TjndT&-uD1e?D6W#;hEVps6MWAGwJqPd3#_Z|~Ob zktEyJk9DKW18?$e2ic8xh^!6Kk1ur}zLg$5WwUKffnePN-@m{;M2!*2{5N?tO#z=v z1AUAodx3S{xLw*z-8Y0@`}s$Yu$O&_;)Uz}f$r#ldJ*Oq(|B^Pv{qNj~-E6s_hj1)st4684 z#K%y3WNzKv8{OqI7Pvv}%K3?7=}LS^K6dCq+D3EdE@5C#Gq%>fo*gcq^Lb}ow#cSy zDx$`9pWtemcnxE{9arP{QSsvv<{n`|wd{-c-}0;e|A}M$|3x48{{hGP>i>>o{a++4 z|I>#eqPE#)?Uy0+wlI{fzAk`Oa0s2B2P`VmAqwPy%_EWaHF2YP+7)KP%#3N|pN?_` zPMej1-)et}v3y{{k) zsRf;ocWlk|G)jO;K6@#Hj;(-!_8~n8>nmL&PuhCR3ajJ0h9MY*CAfG=h;;X_%T&3> zTA;>h(W@$q(Y6ZE0W)ne7?~U5j~AuE`c5Z{ zo7ooI=?)Tz$fGSws6cdR#iquHz3rVbCnw)I*b-uC=&6nwAO(()y{AS6{9A*NPPtRm z-jT~0Y#9y*EYa#T(QC} zkKf$%OBUUPuQ;*x?{{Y&=dowO^zyq(jXH2XJIs~%Jk{E;Yi#%5EgQ}w9tNluUF0VY z?S^;>XT7Y0wZ?SoN8*x|&@Em|FfjLh_mD4LpP;>gjqe zr=T=>cmuQe!+}w}_4O3u!9o;^vU{5wZjAd1tn^M|e4Be~RTD%;vyt_%0UjIxaCf4x zdip}=iFNO}wnQW?lKR3Ef1;wQ*26fV-zrr+NDONa-yvVi-NKKVCs%+!~2X1*sB;P|ik&5|7rcP+MlJ~H7`6(;;{@$Ll_Z~^^ zOu zRt>HZJoiU4)?))pr#~LQx49f54gUf(pEmA4t$AJD_*I>T7jnj-oaawyGo*C*_@2nc zb^Oxp*`K?IkAq)cs^$MHBRE^?w&o6sYvS*62(k#{l}RGJ?>!!v=bmihJwp7xUSV=C zxG4THNGE9xNXSqBT{NI>)gY#7P`>%oBksPq&q;&{{;^vffGNNEj4FDH{z@<$@L%{F z1MH*vSr$h;0h)wvhHIFc#c0N~i;Acr(vM@nxU-h?{XM?+kBbZPm-(sk*S!?g*Vp~L zj#kn&s)FUD;zg4pBaVRNnoj`6l>rxaIRdNpm%S3Pu?uL>9PzEc=sy;n=V| zU0g7v4bRvNH>jf`g(FjB~<0ry|qPgpr~--0<9rO53y?F6~gkIUj@r9rC0$1p~f~>?Pb@4)O}wXAWvY^-aNc`+4_<& zjV1+`ce|>1mM*p5Q3_ILgxh#hn-tZ6E0#tKvFVzhgB2ehpj8&4HFc7;#0ci^Zm^&3 zj8yH7Cvqq|CFv@(cZZ`-A(oWtbyT$-6xGih6rmb+Nv7fcu0!McC?dISw6?xGgU-S6Cg0);D(q>oYG(|roO z1Rgl~(>CPR`{$NWnyh6Cqndoi8tDUVUF?ZPHzM@Z^2}`BQ(-`X+l-Yt4(tc4t7h_f zjyxp!8`Rz+d-2WI;1R$|@&Q_h7stzwAOha2JQsvgvHd8B6EsZF2gDL7ivZbf==hc#&bpspe=_!_)s5qgmc;7ok z8%VImL7HjcfH_E4w?N39mP(W+Lo`<KldH8Md(ReiAB3F5dY#PaR%&BoW$ zFvCUh?4h5p>)tY~>9S!+sNAy=vZ9i_kD4E={;!9rN#)i5_AFIl-}w4^;`h{w1$PZH z;0Ne16cXL&x>(5fx)F?|V^SY&u~}RsL%KKX%n_w6;v0#WUHU|#Ml&Z+9i`^S%$FQd z;W}SD=PVyaEV~&ijbrvtpCIUc0VvR305?aVb&pXfD6!PEErC2R5 z1?;c2x6^#ZxACOhs<%sS{hY*v;g+u;abZK6K2KDTUIeHXjqaa;LK&|1=W6Qd0cvDOwE3scQ>l#n$9=Z z0%?Q86BFTf<8>US)()1DavUfAwOow(3|xUTCkv!=crTGVu- zg5|kZD!X(lV~0^Cz=ewCp#d4w)77yGW~0;~rdua%{Jd}4B2El4Z`@i|tNoAc@ZZ;` zr$&E=rF5h>`ejw_4py(I@Q_Uh+SV>6nOelPNmusc^V;6rzwc{lG~px%0p>lnux8Y% zrxpidL%KC~oi{y2B&V^Is>C0aP0`WMcD9jCt%EwrLpe=>`}F2Q{o2 z9zg7A^qOt$u%s$#Q7d@?$_ZA-ax++U%a@zhxtZY%GKg}dzm5v-^70e!Jue2MDiD^= zm2O#B)PQUx`6O7p%;IT{YfbSrumB=3?$Z_h2SP^V-H=^~$xg1D~0#?#qXWG}EBs3QHvhDty0N??j^)ybe zrXWHLQlmd)jW*F8e}3cEosz!$)3dWtn@ylSkL!(Wx?XqjM^E3m9CqKE)n0tODgjg5 z$jg{k(s-VU75o3t(0-y4i{}@X)=}2b(C+*n%n@qs1)XqBp5!SHC7RqA12umFNPf%< zZ+~Cl8}$T8Gjie{~U>jPJ0X1a=HA)diAp^muR}lSFk!VR@r!}?UO)hi znnYs<=uAnN9vosRXZ}jEERW+uJp{8R4-@Jg%WY*&hcA6Vv>XnZS1G%_iidLRy;CxH zMrKYcK&Jj(QEIZPyo!eBGQaUH?CV@ePe+~9cF@h)F=a0`$2Drtl(`~{X7H$1jrW2} zRnR|LfhdvTTi%*CV)ZiDKU#meWTaS#IWC&I#+2y8(5`<5=QT-1)p}DQSZ2-HPoeZl zjL{$au+T8L-u2tVf~e-VBr|$#d8%m{Wf8KxKL-RdTF;uwjfyD8-|eHkf9txme%)H9 zkJO4B*DzNxNu^O{obgcN9tN{~lUQ|>d|65nYgo=dZF6|@?WdBc8GuJ0P25d}3x~;w zovQ^GX6WDWq|i_mGNJc1WDiIby9Q1YsYMmMj73bmhCHqgEo!ct>EKdw|lvSc4h(LYV|5E#}|6f}Ffy|!!bM+98bi}D)l>GcI?Jeb( zE7&n|HlXXNA*z(I+Jc?YZ<~BujQ+_>YJO&jmtYW@bQyKEsDGMbZ%8B}rgpAF=qD*n zo<1N0j+>O$y)Q)E<6{fEYt!$?YNKe5PX=UowZaR^OKxgBVSF0npk^xnZzbR~;2NR1 zYcRFbSo7xGyRo_ER3{!;yi>UkJV1-1)I3fTT6}r1rfHyc#n8{VXvt_Ni46ONJPJiRX%|c9P^tCC+Bb=CY&L3}>?~|=Yqn-wWuf-k@ZBE~w zemGQX1zOtZY&KJDz|-oB0pRsfHBK*zKh@NS8qk6r(yYs78^N~vn{VzliU&f};?+3< zA6CUq*3uq?05d!Qsy>>TKdC%e1yFHhx!UzEnIXL?IXR9Zym<}WwYA*ID>Nzr^i&lL zn*6*5Q>ipO&|*_qi)YG3s;ac;d5EWf>})4?lsXs4{K`s?~0JdC5$8>&P@Ax5?OY2rhsoMj86RjzGD89O@m0UJuqk|wI;#lzgi-W9mgxZ0Tb z>Q)ZO%DdB?!+@sB;-pr$hauGq7Q}*RSscr6TdIUsKKK8p^ysVm^IIjM0Rp{^Y53B%e_Yi*UJGv z`R?x5+4=dolfMRhV9frk)Bo&?o8GbA&mSa2w|ya`Wot(3{YTb>?0+Af-;QXR#S%yE zgNpt8llXc7hh{>8)+)O6E}|#_D_*&A0rSCDDQu@**AMzf4gEgRJi#s)7&}RRN&zEH zVYQ%F!K-nf(_<;JsKW{hS}j>V0eejqsoWrz6p<}6<~Jn1zKrn#2Z35D;PDy3AWYpc zh4@|ZV8TS+SXu9(iJPGSzF?8FMv3g<7Kc1u^fd*e=Zf}}xouUWDTs-6$xHiKE<)QBh?@Zt>V?n~@mLIkvl*V5n_z;pkbJ?W7!BRcO!4SAP&I}AU?e`I;R%4wTXRn;1PS>3*sJDg(& z`;Gk|7r2Vaec%TlK_l+o>ZQ-}dQ#lX8L6qy`_z@L*CtJ>uqb2}nbIioi8#CPtJkv6 zW)EJTt`b^y_xJq2bY>8T#{8o!nN{{^xiJkh{y**ORB^j?73lxSXr;nyW_yXKJ9uHR zpNd{OthN(mIva50C|M4)(sV1tzMiHc32bhfw$#?6Dol1dEwnP?dB$E2YV4bp{GW8h4kt)k;Q3IadWvvad19WB(8fZMJESCyPt9j; zw0@5yGR;1UeanX0(lN6h@u%Q?ca^*PJ`#ZzjjMrH2?UIY`XK_2FYs7@V(LHps#-_jvAc){yaGQ zRsHe}(?NggiN)0DvL2%q|L5@!J+qs6;;r(pI3&?S z1?~TSCNuQvT60?=O-}K4R1=cT?PUzCR8v0hgWo$h#Zwwd`5{iI040sUB}8ZL^3G7J zY{E}QK3bNErL4r<)15NHL|iqzx~1`9H4Iios_j_vZa&)W!74e5EO%H9&d-NJf3?1C z$-sHO>!)?>E;hd=x&qX&pUsXPNy)b9xD+d&?i90zwv!iiA9trye{)ga5umdt{l#&- zbk6WF#Qs}IEAxr-Qk+dod@A5Rn&O~?f2fhXEzj{{{=2`|!(K#?d_urPJfb6dLwb8+ zu>&;3O_N&LS5$AfQpUpy>P-TOp;SQvn z)mJHQ?z$EPZXL1=iXarY448on$>4he{X40*dFot0Hl5CU^J)3Qd69*ok4Jr`HfKj1 z3Esq-p5qan7uT%`;<(&>oV@9(RZVWuR==D4#H?Mp!|dcnKzXsaVze&@UH^`wwLtQr zgGVK<;a@b1EBZ;nySj@wA}7)Y$q<2VF&YN+?Ad zTF&iYNgLgc*|5OiKc9qsslq?cb}tr;`zRFQe-SLur^zK_sl8&ToniFt!rjCz?!i3^rgRy9~370^#0JoK*2K@Yocz4Na0k72d2GR5s$bePMwCL zm2T3MVV9!I3YHsWTz^nfD%Kc3?5?ZYv#LY#RMmP19HpbP7_W&9e{aq1lk7NKoBhBT zLb0{yo%!P80mgN88NZpVZKbVBv1_=ys~1|pyW!~Pad?I7_hi;>aswUzD7+V}Msj+0 z#b&jtL!geQX^Y9r_(p=bT4`DYbsr_lbhH*^6g_;_Ewuy*p=ws-8F;@QGKu|Q8g%bOtuCpRz1YqgA-7-Kyg#>JFgPK|(E04lLF+7_bJ^vNu(T^`8NhL&dt*jt z%g!i@nt^`cKD9%7yvW^CfP3=ZS3l7T{{D_6XeA$%1H8tNG78C-5hgz9FA zlUn^!PhP8j+04D)KQW?2yKQ#)Ibg)HTyM8(um)Nm9UwZc@Bu%&!MRRsX*orA)Gr$x z@nA?lDtcj|Z!=9KbWE+%p7|_U`Xm6GG~{49jcYI_wiuwW>ztuM8Ne#jQlR_U!qMZa zm;Vss!vB%I4?RD*8Q6^}R(&9l#i^`JTp!I#Yxf0k;0`RwdE#;E?n^j%=gH7Kwo#4~~t1myZc;#m` zSqbW4{F^oQG7s#dx_jl}!lLCh0`W&C@ntuzjgfq!tl#aX(>!2gZ`j-*5lzRd*trIO z$ecaT8j3HTp*9eUZ_6**a|r3Od3{m!M;5lXS)%l0JE)|A8oEd}s8RJ}O1XjEcFc%jlDTlD_l4(1tPAzL1 zhJlqH)-jDVs22t-tK%}@&X%c07>xDyzPxcDy>Nl*GkSBMm&`utwONAl?Aj$(W7%bV zzrQ8xLWC0hN5roa3g0$cmM;+`phE_zhP>**n2+2lVS(R(I{=SiD37+_l9{r<`V zOY!HRD`*8X%(V-tJZ^v12F`t+`!=*QqU;84wLDeEUIf2P`P4L!NY2QGiL09?P4zb4vxD^}C6Izkk;7qCIE#z>A$Q7(vl6+)(?>aU<-$lD!sT891 zuD=`VsHQ;*0O~!iw7wC-cgE5547HC}E&pcES2*iD^W!t==#?Y!q(RSoFZ6;@9}!#x z@pN}8%52(&7u~I&cpm_m?q}@t4(S+fLo)F{T&ai@5EGHS^5=i`+L-<5r7xJ=*!AlZ zq>OZuR9TV#q`X`i9M1f>$=*1sTo_X{PQLS9GAZ%kPf@~a&wWM(jb^G}e(xZ5whG}u z&T@0;X)O~ZJv?&aD3}S?Zq~KlP&ID{37b=JOu0_G3(6Oz5BU(Ze!jrp*q4L zw0|G8oMa1ie_g@Qi_P)Nyppa_OU@`31zU3O9 zOQ+bN##yWFghjZUF5NRRli+)@x?n44k~XpA<*Y62bhKPH{X&^kz|bYnJUY?gy{wA; ze0IuLItS);c&3p3RUMC#shxRAI3jr$0b%GT1-Z2c!~z_py12=NX2(DLshkMTuAlXk z5dCrsB!zeJG_!d1YH|5|cYOYRhvQGiP)5OTAza zJB(*C|DhM;@M2wNSHYK-GNx>}`?*H*UV9JPp`=8I{{V^h?RW(6BLJRoRp?s~f7-vP zfyYP3cza(C(1MIKd0(-s2)V0@1k7^6zkBRv8V9^Jj=Rk&{k+@_!sInz$?wm`rjCmV z-5%Mx?eq@gS(%I+w#sr5ty;IX#W_5r5Nu+NmofaJ472s(uLE zJf}l6dYpa$_qI5+htqV|jsZ>y9N0j@z$Z5W=e0yDS()O;XzJBJM;3lAm>G#pXh>cI z_3~~9uZ{5A?UVM3z2(n)vlhEaL&FT^)`So6b}I}|Va?aXfi=)5)H?)VLfR8unw<>2 zdy2hHsGId>P3ZDn${O>4&lw^XHu;rz6u=CL$#bFqk-@&sjvb}gxORf{nRGMJ`RQ17 zLryRxU10@Cj|wOaw2%Jw$idH|ZVVScps!BhjBu=Is)}*2;=#cZEql$u)cNX5-%%-)X3G^)<@Ah>ErKAoT4 zij@l-t0a+3>Jhiu9icBa1SqgFAPWo3)bk_9%o%#RsS3=ts2xlbqsw}Jsb$ri6}UW; zh4YBp0L1LTyd-LvaG`h_kz^ed4{-c)#u* zolZ~1lG(jZWM^@iS6B;r@|uT|;GZzUca);*{4k{I^@ypju+dRgAs!HZz@Z7r00eqb1u>d zA$wasaF#`RtoO~#fQ0N#=vQ7*VeJ>g?zS0mBW^A;U*dvj5{$&Dte(9(c)Z+wPk`|F z#QNYki`SjW?tsoC_Z8gtt>5z&8k4s_BtEn>-3LlvsAnMcYRZ1}v>9u&Sg5QaFh8SW zjC?A&7Hg;41}11X&+f?kFa?`GhP8B_fP#Y>{PhhMRyF8_HtINXT!_0IYqvx(@5~1R zPHsAI3)ZL8i8{=)I5!qaTwh_);D3B4{+uWxs-;D_Ll|(w!cM%@T}Zj%J9MT}{}m+s z?n9HRyy}=OfcTPY-O^B&QSp&6@uv&3ih}GO?F2kpx5i21rLmvogTVKE5*^CMjW$e= z44(m4D>5*F*V{|0UuHd>AAP*Q4=v^oB>TM%#rkr3>+w*1jV{J~j|rB(a{1?v{Ieq6 zf`T#zgDA8e&=W{6#>>!*MA-kq-dBdjwQOxR!4n|31b2r30YVc9?hf6!y9a5UV8Puz z!KE8_8cTv}u*M<59Rdjw0y)#i?m73|bLYD=^Ud?jkKuXtkG;Eg?NwE)inmt1Yc2kq z2xp<{lhGo*BX94W7XIDs>HgaCq>Yn`hivJ!F@?N>wbyT3;M23l-hz@8`bk_XKA|IL zMxBd0Le4J{{=uI*UaXsxec`9dRLtJZs7~r*zC@-tDg3AzqYHV|)Z#usKP$lYl@?k6 z2#qE)@7?}5WIjJ;3&`8$m^CvPnY*94hJvJAKDhL3@VH5E0q!jvR4Jn6%k!!})&CHZ z5VvA;e|1Q=g4ctp|6`&O|99_V+Da`%Yu(xt8??t?=TqvnQdc}a*1d46-LWb2Y?+RU zij1+@kkbNdNhJcOUO74WKbiCT_I=lpfJsv!QWJ!O&W06*;pjVZ)DbldE#)al0GxOzU+aHq#1MdA*0roq^Kh!Tc!A;l`WIW;!T$Mwd|AKS<|~f5nSo4 z%i^s92L8+h_ef5j8cC*j?``LBEWR@EmaAH4!yr{fw9E$ABWC*@mEbkZB& zH4)XMgsxm)HNY;PV&FAbM{p*5O;GV5>GFbJ#d+MO6e9EuN*o^|PZFsDZCTN_FCKxP zHeyMQHAqQ`^DXV5P0M#nI!(=GpbcED?P$L15=7N+>2K*a6nx#VJ5n_27P#LqZ#Fj< zz3t5Mu4A|ox1HvEitH>xtYvSV1aVy@!vhs0trii#J^*+4IjM!f1Nnj=;x#L7YgO&X z=7w^26ir)#YU}ay^}=9WJK>?0FX!Hv#2n|z^ma`tamVDCx` zpsS3y(WgK+L1C-;#8<7p7IO{oaWTJ94iw8gh+nRQf3X7=*P#CT5wzRkHXg+Hkz=Rg zl^}yCJGPnhQWU>nYm*N)-QyVuXWPLIbto|9Q0}uU@?bMi{os5Pnb}pdW|ozbBNx=t z>B|X2Or2)+y$M)xbU|?CHGMG;Xc#WQx_>g%DsfyJKrkX?eUW+c#oc`B9yM;{Lm=E; z?ddsmpdY?sZtYL)K&-X;vg=`tQ5w{}VVn_K)pQ{wRurV5GPg9hs*eQjqC4;0R)XhD=*CEM_$a-U zS*&92Mf03T8_&9{_tL{U<~|RU6qji6foXM1 zWBYQeb9HVQ&e`BqDm8a`H+=f;Wkgf2!L_WwMM8r89CxZOW*noiC{}$kV;~VT##XHt zt(9!Y_d(4mrMMhkcix@WD7uE0sI5KquK0eK24yiMtBqKb1N}wx5^XVSr{4ATEz&hw zm&m|4{=`w%P^lDVyhx9$AEh$~x_^PH2S!-ccW98!f6iC-G2uVjC9$S_V6-c3?Q}6c zK3CLl?kwAjCLz`zMrWL1*By0k9)77E_UH%2Ns3_TJEr->aUqr_QSSK09F43(Rvmw5 zZ%(aJeT^RH1^9yu>5l}KOrNG@WYmsM2ssK$C%%#losx=$Dc2`*ONaw*FFj%-kq;Lz%;{qS!Xh za6(OZ3bUlHj5_a`r{!w&;O04-wC0=9CD~Vm9c{BtU}tQNM4t!7e(4{p(IBXEY$N_0 zFQvx7^R)wKUqfTG-KYx4px0Dz%X*u-aOZ-hoH>~N#^QijDk{81)*YDa{Hh_5sp88c z28Y;w>l$8qL1LlN;HfR8)+~|S^rzrf z#b>X>H+d@^m-a;E;5;#s%hjcjweKyO?%>tdj(RHGCMRbpGh@2 zuIlGvMSL)U^Qm0|P0uy;v_H!mJ(#8ziBI#zae9|LaPl!d_9aOUK8fE5E$MfZBgnuw zG;%5iI(J3pS+y|30IhdF%cW!s7c^Fr5{m6GFkOY|y4uh8`yZY|Y&`T(qOjJij(@Nm z;X(w;H+UfXhY0psQk#t(=A=!k*2mekL*L^!9Io0{n#!dYVG|X)j(x9swPY7F0qoOG za(7=>DzKyFUb65AZ{jhckZ&O3;}b(2VfIc=eop1ix&rp`9tMWoy|~oXLX?8ihK9XE zV?(uMDI;vHtJyEr6f7{7YXsqxl{!}rDWz9!9BLC;)C9A5thlJ}F(`qy&T{U`hWaHt z@%?H~50z~C76sqOhvLbp8=HPQiJ7-n+pr*>cW9##5gvKscV^?5%#bfZlxT9rJV@2~ z(tLj*Z%&>e+}V}WkZq&wZR;s@3;o#DyZXsyZ!ssq7r`Shj%r?Q#1~fgmebrJXqlW| zDs%Kzrx7}uCr*=8E?a}@9`V4jdk`ywmPe8EYmz4!@weYTxb6Th$cRa?qkk^N;WEUIVv~DB`$WX9Y&g*Iw|Q_9^Y@KgJ*UN z3GGBhZ;H>^4=*B@R0~QnBiHa|<|39JqDuWEhuf{{!tMj_M{6kQBtRpl4$$Vv(RM0? zA(&}#Y63$UGmM0}lYOvy-^gjD{KIOs%}9K^f22Le)==pI6xvLmO??S%=*kw`Fsy~8 zp3e<*B=oBocY~L8DJgW=DdFImq*}-2qGMyI=`ct3K_+S0!HsSrX--0MW~nRo3Ft(W zroSBy9qnB*w}>Vg@qu&K9J6)02F)E143EknlNh0^X5ZgOzt6(o&-d-tfxqp?>8JH| zz5&jas&tPwt>&HQ_#Lt>gfQdEz*cbC0IsRCr34)31l*}ob8fX`5XRE8g!J_$gLTlJ zWr*r=YG6Aoau|~HK$plqQ(JpRRBBVvCI~uv3{s9ie8KxZ!C>x^BzvIEjXdG7Cs&qK z;JqNHB|1~~3Brb}*66vtFipqhiN0zhgWAKTP%KXhd)Zmt8>u^2bw<~gt}q!Xn_RhIUh_?wxlPo8a9xG2 z*>tlj4`k6u*wF~_A_>@&aJtmlaML36MD{F=8vVMx!9~HIn%AyOu(d$p$B4F5OC2-I z$9yaVT7!9geB)m7>9;A>Y*JD?KAMw#mOku=D7WnCR5a9A^e!7% z(=%AEf2!`e`82i>K$RZJWn^U63kzunzxUVb2}ED0Ew#6(nJmS~EKjcAQ+n~F?xsgp zNl`+v&k=*o{>tFTccUO97`t25YiC7gSt)O=&Y@ymi=3J@-5id{ppxWi9by*Z_->LvjW8QjG3>q@FP-y&su?ptImPI)w&}%;1c?_<4SY$&fWCNgpSaB=R{Plp zEs9s(i_02nbr~x=K_|KED=8M|(U4gJZC7hH&!84jI(4`9lFg`xUDM=waD*bPJ2%9oFxK{U(`qWf#vgR^CC8s92%NDW`oFG- z@Ne_Z8|Mh|uNeh%KYn7Ld$c@a$vTVgbU%tX-;xazu+I?#2pRWIhB0@9MTfbx zxZA%sG>*acKFH-ym^o<7ACb4IZle~JdDqAJU2@2ZZ8_GKp(fI$-|DLS@d{L8sUtli z2NzEAxiU*k+o)%@OYcRq<)J9kL|@D%)vRQ*P6#&%rApr7p;r9uyfJxmp^GMeLb%Bo zksVB*;BknCrl5*6hHXIp(I&{vkpkz%XM!|`UbO^4ZxfYNG*I?*TS&TF!CH#4PFgmYi3GC4$^63w^`q&razeU{UM%*j z{iYLcJc`rMweaB~!y~06^rBK_{5q~0sQxNpx-vEB(%kLhqtel~sk0xh+(2N6vZ1-8Lu>g1hsj!zL;5P8*<4#b;P?3HJa2>I8k#)IS{yl*E8Qhu zwzkcCV2NjFnmantya8P9kuR~og8(;2M5(eDJ9L8EyaA8(9s@{var?Tex?ZdC=Qdv9 zqboNLnia|#N+%BJvGuocTE52Q0RFh68*ttZs(U$0S;kl+EVJD4rb3_H#lS*V3MPt<%Ax?iA06^Vp+FC!YlQ}v;&#J2}r0H^}F)3^yyHbqFvzmzfxa~n^rzeXPuZ52jq$dS$(aNe2{goM| z12XacG#&IwB)15;`T}ALh4J|%F{nrj3(@a+pfHF~?GwL+E$GMofbby?8)OxQT z5Zc4jfz|Gt+m5L#j!PZf@!p9m#gY-t9)ru=WxWQ-1br!lJW#?3h?AjxU1)TmQ5q?M zi{XQcw%vw!e=-?*rDIMKy8Z1kS@j^+?;`z(3fuZ#?vtH&w92y~74^Yy89Y$V+OmZ#F4H1mPB53dNeL-ieL`V2cJ>gpH;P`X&VE42X2Rea zncf>+W|J;Vld!o<++jiaoXjQBV2N$;&mjsdE5W%bExDsd0=xi{(rw6lQB z&Y%pSpjtRNhE;1CjEJiP;OTg;D1WTYvNEw3k*$c#__b*~P(dRLO|)-`MWqg?auFXJ zL3e`EH<(n{GpiIEq87ytyIax&F(4T1%j2{`;Vjm28~NWc0bNIX((Qex;+V`|299&yBQ#S4Ve^K`0^8AZ{^`u z?(>6yxbrviJzcBce{c-`1Ze5#;v#jQL0A$1q2gB2V>uJcOoe{HK26Ud_pia^KqX5+ zq@oPww|b)8^`{>r8?Q&ie*zHD5XE2nKaVRuJtO%4PydhlK{T9CO)D>geaJl|$|8!q zj6JNRj4kqo5}g>`)99Pu6WG>do}NBH#`g*nMMiG=81Fl4`D5e!d3xLFyKjoyMm^s@ zuAZ)|ef~ka8cnxLD`w!7Ry($oc`JbWc){q5MJ=Ub(Sa3n zC_gwkwW8F26l6Fb9n)tT2jsK+&5d$4540c*Ux`;J-_NAIEtxHEts?>2!yFS^ouXo_ z5GFKAEF)(R2##0+%_1V6rMsjIwCiOwKh5Y?VyTzvpk$b%mK#g3VDna2(TOrisE>_K z%}tERG)_~p*xWEow$34pX=FuBE%Z4-OIyWfYRjdLxjTftEQ=+ofqtsc_oX(}jgb#O z7Bfr?HN}{wjf49Rh$YbO$`w(?IO=a!a~`QZrrU>6m2{81N2z4u5k38ErxemLvK%>A z>#SC;)7%g&27l-$hHdZcIY~OC8i}B6UM`sH=V(9@F^qMlRM1LENJO;huqSke?s-HJ zqwPK>7MsGyDY&PA`d;nLlJ!U03XJZ-2#aC!VBN0oB0~_-V2V@XM=b@c(6i$k zSfbN60+hp&Ul?iZXhN%99kUJBvp#x$pZrR^u$f3!I~pC)#aYAwffj)h{whOPGcF&R zPt!zsmb*IC7R5hwi@v-#0^YgQI)5~sy72Q`E#La;dBs<8bawqLFy}G|$t_PlyzUgJ zx-sD3$}h>w3vhd0Ow+L&pF>m#QVKOqTbJp*k)1%}g}WiMaBbZb2K6bR4yeH&LOp>G zk={gmQW-x1u+R<dE zoh%Ak@1adQvxm0+Kf>UUoj;s2|vvzx=3C&<%FReH+L}PSpod+lqd5& zryz{l1^nuf^v}rFKj6svkX0`ESiZ-7Mz(m_6=}bYx7-EHZ{6~|xB;$y=!rNN>#>3V zn*MI~Vv9HZ*gru0Az9?Yg$>N3<}laa&og|n6RlVY(T#Dc7|8OC$*{g%j^U_zzao;^ zGgP@p74z^O9fpVwL&R+=U>lTK&dyy68r8I@c}>k-xnJ*j;jL>~iAIap6^DY~Z%TdW zjwf)$eMplZ?M@iixrsk?08kwW!3vI?LLcSiZYul zH5b5apB*r866wKCUESo>@(Sr!D5`i9>=S6uTJKHkSb^l)zX9Bo&tB~M6Z{%$njk7p zW=4p#v&7lY>7;w%A`2GIGqNa@3fWH+T@Twzau1s;$7hd%;$@3FrA8cPiq5j?6+fb?kw9FCIz(c`I{qamqIz2a$=r_Ie^X`YrqM-W{a8EHan7p)6r=^Cis6O?uvY}^A>$xdj)%kQVTkPmK4NdeJex)Q8Y2xj}GIP8neEeI~ z41Tx$v4KV+W^c=-xHv&ZkQpeVAXE@7UJ|MP$X=6$LFAP+!%z>Aeb(AoH;xK&P<1O| z*My(y%x+euEu@<~wZ)~fbqt0lxqG|5?hInsKFZ6zQm$YqIsxlj0#IaDwbD@8tGs2Z z6WixP@O|!8Fzo@39;N901n3(ZgV-=F7)&`eAW$nEGd&I(@i9tn$|Z>XMo8p>0ZdLs zx_@ZJ&;M?IVL%e0IKbW+AChu77lv3ng4-08wnHC}!X5On^vje76&uKq(Niz#L~K57 z9TR8@D$Y!66TiJj{_Sa#jh5TFE`&>xQA?~6M^qBCE;xYySlBSp;iKZRL%!ri;^n1E zAV!!fqUqqWdmgcHP|6RZQE0n=t0kwJ=Fd+p8>bZ$3G&9Hda85C125O~eoz4ciOh<` ziL{!!NMG=XzHz9X)zN?!;Jt+waD)`x2cSywLCfGo*3z;o<9Aj4S(i7Z(X0bDA2Uja zzkrxB6=ld&1(Wp!N*XwlpiEFDVud0HmKTK70!cDx$Un>i_tjZMvbLrlZ1Mn<9?UT! z7p_MwiAIej_R5PwOLT5yWY~~66bpziZ%3CfDfyYg6!M(t`n1@o!RrnLOeuzH{2_GWKtMv$kB9b{ZS>myDF%oAyGpxgyaLlEK0oK=yQIM z!Zb(xNdqMbmR$5|sUx4xA|-*pM!-ouHY>LP30{R)S8$6p>(gTkEc}OaMiMG?NGDTi zB=Rs(GPMv3`@veRPmmZ7%7)Mol)?9&H0@>R8&9CLltQEr!t08k-n^QNl>WrnsHz5E z0cX$QcW6y@6x*LwI6J1{SR3?v0TYczJ8Sw-HLP(~sNu#X+ISgQ6jn=2!6HCxYM063 zBxT}|L}P^3z0%9-jGzOEag5^UOI|a;J~CyoQ_ZxiL(Zz+bh!4M#+crvk02ss5LY|1uRlrWC6Kelg`D{%U%|2aP2UyrWpMvffSQU3@*iw=&yz zfTI3mTiWF)0RFjwkBt1D#QiHg;QW$bj?P%|ux+iCyVrbVnsF@sQ!pElcwlH`u=zwo zR6pfSP`MrZ$q20~$b=CA*Y$Avj*+nH->R~p)$Nj-@k8B7m$kBCP^w;~`b^4OcGB$B zxok64ibZIVo&0RZVu*y8x>5|mYTAqV&N@7SXUUMO0RZ^bz;Ubav21m(8K3@zQsCpqQ0nPC6O49zl@tBaY7rYvN!q39>ZZic# z+jlFYT^WO2oz&4-eB7=_(aGo0ojl&| zFo$I2JB!~Lgrz_nqYS(VRr4$4BF0U$BN1M;wL}SmVQ8Sq=J7P~x_Z+dkcOe^!e$;~ zUGQcsg-+NE!F}>7y|mE-i^X%{4Sy&ckJ#c?Hd!~gZA{-wSWa`SF7j^oo7bqF zP&F&tpSsNd0+x;ueXNH#$SHGt(H>g|dl~9V&3_5Q7?B;pZgXmk8c0l&(XwS`SlK9k zx%sNu+QCIWmzu1Vy{!se3JN)|*@~`qdUW5p4%+PHQWXxJ8xzv`>%M~nnMF}?c zK3hXNz8}La;3JB_v3`r%x*}02al$fiH7SEU2ihYoq6jAuC1gusUkDdQSxX|p%JIe9v?#W{L-6#~T|txStgn@O1SA%lX@ z3`+cin$elSuE<;Yc7y$Zx@P(^E{@|JKh`KvydgIyDm{w12R2dB;p5!y!kW@;ePIsm z8NmsAvavLjwkVU^F{3an&J+nbV|%rHAkT!l{RsuMG!33j0dG0)To1_chri@2yI!7 z2*WP-F>HYBWcv=iIt%tB8&A`-wo zQPi*8P13(v3H_m?p9ecdA0KV0>l0Kt?El!XRk7EG5Ia0Vdw<`#mP%Zl)6|q_FzxT0*_0Q~T3fr$8v+_tB2p=RCLllrqGtyaqnQjS@aCx)|zL>}Kn zF;=IR8~WLKzS}y)dIB?QcnBn;&Yq;V}e83Hj)%zA=Y-(Ac?)b{(w}N59gd zi)jR|wp$jvJBJx4GTE>!JXJezZJ9juPPxA8bb8)v94LAyNO9UyQa>sZ{{?UO;Y+!h z8i$(`{&B}viHZ@LU14r@b9$y9%~rCb3$d0F50#4ep#u6kOFf4yEW%q^-nY4%Tf5da z>#tOVCb~F5=K7$sstewpC zAR!fvHRZ#8AGN3`cx~YSHdWAn=vDMbF_uEVTV$Fhm)Rggv-4Q7^2@~2U)`L31t`z| z6E~;-R)F$HilhFmAWpZBVdtqM|BES(e%^NeV$ULb&=+#b)=`Pvhsoi00Q`6nmtNFaYnIFAhOVk)dHW-SXZJA&9?~3 zfAz{R-ItPllvmQ}dARp@PX}K>a2t8>`%Q)@ZU2X2Fpe2{H6e_qw+bPaG(@xDGtd)+zcm2-fdgsNb9W$Dsc2 z{PHJ7Fz5fXBK*C-o6!Fw{%+3&{XL&S96D&uL}rcaL!)f=X$84CywnWpTtfFRqot`C zFG%Pj6;+sN5|RjTs*R$^11%K6hakC3cn{pjU~31TEi) zsAbN+V?5#8MfeYPM=b|LCj3&OSo*o*8s`YtD&CwvBis{_!{TAk&?I5h^&%HsnLk?b z%CLC(sa^?+$cRZQrov`L4$}4f?LdT6&1#FqqOHpuqu2Nl2UkPbq!#gW^5|Fc1puJT zdpf{9#&kl!>@}0>AKzy`U`=z*^U6c7{)oJT2rD+0nJN@_KTZgiKF2Prr zC=Oc_`zp7*r2-)uJR+YQd;>bAxnXoZX8}fUUOt?Q$ML-|IXf*9`pAF`R`J~I&Tewz z_d1i#ey;OnlfB57gRaewGS1yHgPPA?zWd`H`puu;8TgA7FPrRa{~?FZuaZ6yc=Jz^ z&{jVp|L0n7rV8_Zm*v-bf0pIfL7;T~U6#L$0p_9Hzkd9WZu-kGMgKBPfAisg?xlZ~ z?LTPouOB7+O*j55*ME!XziQZjDf(Xr80Rnj^(USE4?E+pHU6wJn}3-He;M09y+ZT% zTK0#={KuX1zo6QG_tEaZRntE-h4DA#|6_ir|E%grrTnjS<6nyWsrkQ5vj6!QT;GKu zM|J1t`BnYf{Q8?3$6t=y#Ad~+iHnJ(8*>U6=#+w+t?ZJRriTg7Mq)&K30E7~ix%4_ z7(CK|4^Fo64s<1Jx?UGvY=xBEZ1b}umpli4W4?8b_z8dq#}uUrx}yxaO}D*MPkybv zcXid#6V&hX6X0^*yEJ6Nz^}@JHMg^_=j10qHQA#lHq{@M_K+dyN?jarp?%?GhN~d= z%Y+g1TMn~~_Yom?h#DB?yqp-`zp=%z_k`EQI8D5~ zZco?IzH+8~0b_^1YFEXGi;_gJkrjBLkMw0v@6H`68cT?0?!Y~sR#vR?`o>lxoG}?s9t@(+WZ0c!FPxrA_OC|9 zE>HCrYzV5iJLVZF!dxv|={M5ysG`=!WdM&I<7fhmE%J9Qu(E=s^R2aH6&i2HfOTJo zMZV@%2quA`reC<3l3U=p!}T2!v-~G=V22r1{#?!#3`%=f4SY$aW6gw58Ish6+lyJuAz)l-o-h z7FV1x^V5n%=7RO0q-4nBAxrx({1VzK90Kz5>S8$Xqvoen%V}OR8Yy>Vu zIn0Boi1;uE8%*azPAVFTn-4$S8Z&Y#8QpaA1%k#YoI)_de1yPG#&3xZaG#~D>BhE5 zknrjW8d{9Di`Q??vtF9Ce;zMt#cr$gTjP*7T`K3OvZeuY2hMaDV$0HPQOU5qtIEw7 z&yGuu3N2SIQ8O~~u)gkPPd<#X$Rnlo zI&YSfI(Lt3;*>Alt^IyHG4dL1#r;c=wYWF20fw&|<%XXXm(NEHfW41%RD=%6D@Bbp zPABQny0GyfB&HVLkZ)d)Mm`S@4w58)a4euYAoxRdNW6oT03kfQzFEJ{FS&8A_dd9T zZ))`3Gp@0!fCjQ*03RZBf1OR#D!wex{G1TZo1pG|Gw{8|m#A%j&R+?>sQ}W@-_6lE zG(zYsi(6AZ>q83!!>q7MbexJ{C{&#ui^A%aQ?qOCQt)r21O3p+=&;08*XxYrKt(gv zrTj6ywrb*qC5}jo4~B*z3FH=#T6j5ltd*wxQ9`3mA0Hs3PW+SZTJL!N-621q0X*BTyGf^IZHbt}Bsq?U?k?s8j;+{?lyfXh7&l?W2%Pe9 zRKlO@6$n*Sy2qE3OfSLS7jpsgwZ;NsfuKc0AMyv%I=$~H$m4Y|IGy*<3=tWZC3gHNtONi>f_pCOA+11rh=B>(9+kD?YkGv z=B!_a7HD~`-FV7cNo3`YOoSy4pocAoO)A3$`wxs%!x)p_4at&P?tZ?FkY)QZ1+73M zOQ}+LAsGPSP-Gkxyazfte{-JaWvsqvBg{BBV_Dv+%wxk!EBBz_GmjeF?*7*sc)n2i z%lde5_-jR>n`Owb{k3YwjHc?jVz`u`F*~Ifge%@>)xLOv=(Pvf+R~_gbc~tCM%K@Q zI6{O(R+h^2$Kk1XM&)&1a&(*hX(HZuj$=WqJxRtSA-VWOe%I5j`)9pOE8aqcCqoa` zO8^fdFr`eI&#Po`M&S6A?qTV0q)&N5HzGIJ(STlv5#y1tch{sBysmGq^E9=+$(Jg| z)sai5rIdu;I4L2C0^@|#XAz_?q_>(xRZ3qqpR7DJXqDRXT5hg_P;k#suW8x%ySKAn zxV(>AS#A=pGBv;9qj#z4(d(^*F(VM!T6D}qnf6MJ2nJf@3o z!#(Kut@P^b>a^2GYm2%d>vdw9_k_^J)o2>r3hE*4Sk)#&BtL0_h?4RCSY01J8BI$y zZd?E=B!k;QaNfIh;k8co*Myz46`Z5N-09_5WhF!@#Q-pR8MIfCl#O|W&G0H-&E&q< zJ6y{+SrVn(a7{h*jwF6oHuB<3gCxFrIw18NkYs)oqYGYddQIMv-i9!BBsn4sF&BQM zR5#u9V#$|D{1~IVxMtP(VOnmcw|#1cex~I=AM7BH-&Dk+DFy|<&0R!}F>=+=Z%x%I zDhX)G@r%2Gl~b6%#`$qJgT7!Sj^)HMfVBB5)08mS5)~MHU3+;Pod!i+{KEsrtmcSP zFCeBc{pJAyo4MxJ0u8f`K;bIwD4P-Xyb9fE(LS6Q+}uv9?BHQxub7H_qB)#jw&uU> zRnw>M?$#l+pKXJFbez=!+lq(0$boecm3x+*_b;yH#Sot=8k^KOOw-X3q8 z7kQ~oAbY})cY1ow!3xk&+B?E?#fNL2?uklR$XG2&nuia+hJ7Q{Yn@F*JKaLkVXXR) z1_TNM3cf!dSu*^*uO3EoYXl^`ldJn8muEAy#aK;HwMfx$2t>aXDZ0;*V=5 zcgS_z5*g*vcrD|Bi2Xr*)N5aN!&uawZ`K2bV)J_Mj#McXicX?dLw1R>NH!VExm3(< zCm51=t&(z5^}UbOtPl>1p37Om);Mpr67)Cr%4&4eN5?c5~YjTCMc%mK$eRa5wfiUSugaDGrS_0d3`=^46Al`PKq$63n_Y6Bd(zqzNcck$^xT6N;ry{F zkCxs|{L8zo>E(x&#!^+m3Z^;`E=&h@rh4b@g;8IUIsf)?GY!lh0iXGr`h!LLhENn& zfGDT9b`n4XevLNhnuB*Y|E#U@d{F5iO?b@cb$nnU@6vwtNTYO|8X`axw;qS?nc_j=q!hJy~pUhrMQMh_<`dvv0RAgr~p2J z)=FGjEh8<-)aBOZvY9nq(uE$ZZ2B2q4YqUNy$+CE)k!*E521*$K{d#iY1tISdNreF zw+;!1TD_l=UvI61b4-!xLsRT{J+Luxa|iSl zML5+k0?8WUgAIqAd9BTtP0}R+3yRLiO#)zGS=`L^N#1rFj-_=Qu7tQI=RhV2cet*^ zyeo5-9Y8{%IlaScB&7wSx}6SR1#f3PHK$vX6QF- zUFe{kAc}csw%mkwV%NM4jWAhm%!GPKgA-1bj>EE~x443Zrr@LidOp;vWBbSE+KNEa z@dPkaL(`L`ZCQshKP0fQrdqqfL$~@_yre%NK4_6ZwS=fWYHnXZ@gDF6h(u?!ECro@ zynWkoaL3*MU8>_FqU_DJoLOI+hDA>Mm4JM;j0LiKN#YEPvOdYM{)?vpG@^LPv#p84 zg~P0}ZdyQg4Z$N6$;Oe-OE8ml!}g@>m!nyE5U8U#=R(^ck$IU0w|n#8v+(#8;vs14 zvDJx-i8H6af#fK?A9yTF@g54PSEbhhSq&tKJHX<8hm zj+40H@#yxCE>rC-q3@dtHWHq!s$q+e*Cv@X1VlW5bSe7^MzI%2JvgG%7Db(#+>$g6_5~kDev{|h|aJ;p)4Kh?Xo;#qnuu-r;5f!*)%9%&$H-hfR@Ws$8tYJq3|&b#z@prd5RDFpgpp^RY7NO z?Q9_iY6liG!w{-mcpSC|IaeHqnTXPF9Cv3hx9V5T;yDL#`d7esozvPO2uJS=$_L@L z`s5#dMu$fGYZLQg7H@4+yBGEB80@&mO9UsrMa>9t^mUoc)AOP<+P8EC22_K~9EF~! zv4{n|mryuwSLsR)C#;AV8LSj>T0W3-GPsvAe=)Xv2*k?|UfOav+3PKL z>4xX~tOW26xx62$7v$VpO^`z#EC4iT37v47LwhagsDp}n%#W*d4(Iaww=k0vmTD3u`Nw;D~-ph9Nr7Nc?mQRydiyaVt&2i|9 z(v&oZAHE_FR+dxBz%pL-T6{A7_b?5Gbg4k6fxhHRyy%I&yX$kvv?qzOPc~n_vDfxi z&2ORvEyfbmx}e78y*~V?rf9Qs-X2HQfr@V^)4lAnvN`M$!#{@yhgU2;3jmNQ%(w*Uj zaxkEKwLAw5($sLf&d`dY(KXDR#LyJ=yB0oc+;&;uaPA6jtUGv0(Yfw;?n^b2?#?#u zUGIPfhScjk;&Lv)$C_Q{%rjb^9i_y$Z)(mD-f-kXrf()J$`3b3@;iY}l=}z1Z1z?Tqsisk>rC zJI{^dHhaxg)i-9y5mQ}eL#@up<`*~Zz)>5vVMG-3W9LRjDr)~nEn<(9;`M^{LYnvz zJTZye2_!eYegfbg4#w2nF6QD%YdWMJU{-@XeNzM>qL(7_1M8;m#1-J)FIq6Cqd*`#CF?C$-z?)tI9lEZ5 z%L)o=v%QHo-ZswU@f}X{XK@TP#jdKQ38Y|1m6)8AB)BvoPIR850C!g8Cji%u@tk>m zZfrIGv0*!HfPu2}dA|%@mEO9J-k=-@fSP_QW$SBvXOlMwGF?Z0{>{!VL z0E!>0#!25RxIaJD*_-{ZM+hu5eM|PoFCqCZnoZ2nE6;N6D9V%9xh5Fwy_8GI*bcZx zTd-NiXsHF&R&-QI+0pVXzJ3j5##+}!GjJQfD|S8ZQ1VYr^QYdt$_zyMg^DPNG;YHO zLo0A%*g9;6J%`l3ycV0PK}ed||f_dAk9qBj12 zpt;|X+wbh^UtruHH^0HRe@2B!H1|h|KW=`3hErc7cTJgk;y-^}pO@IR{O}W?_{H-S zq^ox2xxh#u&5tYZ)9YH=A4?}+>-0y}LBAeb{cUxBM$P}O7$MxWr<14n2hKU_Z&dJ2 z_kT|X{|A1x_yv~!(l+v_K^Q?YawL9(wSQ^?ozv25|cL=|A7zM%e=pa+q+d)xB1(#f1 z*gRq=R#-HG-Rntwb+-k1`1H8pf`F2DW3^%#$1s1;qpnLjqgH!*j(Xav2}MYjkX`I$ z(N-oXP@AaV=Yv+y?HJ|x!|#60!>6Gu%*!qHG6T-tHuUJN+t@78M#$)Dr5~Ku-Bgkk z>Dh_Rg?1>G)q)lF%9sdAz1fbES;Vn#?gFi8D%WIL`+^LdSQZ!I1HeIohrV%Zv13Z7 zch7OYO>6FUJKnvzJwI(p=f*mx*x)j1Pc!FQZ4V&4D`2y%;&^EHx$h@{0zAH@{v{Ob zs*}Cfp(?a%8riIKH0er^6ka!XL~y)au(M&>$~Wmx$w_|9JgF1PtjU=6RtztngD6IBw11vP|CmbuG;^$wl_Iyze_3XKoryBP?!YS2!rcEq_B{#J{iA#NeIENev8P`~? z})?Ae3ZefgVZrkiX zCvd1E))xzSJy0cu&8cxo0m*&*z;eeqjaah7rYb5@FI*)gsTX_{eaQLHq!k(pE+{?c z%_7ML)^k7p+MqD#*fn{f3y!|d{jQnPVRc#6Nny0~ieQVDm_6p> zW~sgi``qKLvIqZByv0pqKI(3OYO&}U>i|ueF6rz$cr5*0g*d;El&he`Ufx~mxg}dM z>kyPdtxxTqMkv+=gM8*2gI(C5!8DT)^=4Wc$DPA-=c7QP$@TQ+@f2;R12PqgqXTQ3 zr1xzH$1eVIZfpxoy0M8q7lQiO z$t%>-H*+nx3_T6(=VP;p^DdJw)*O=U6O-r_+%%bt(n#2eQSqzG=c4IAVy-W1L5l1i;?@>$J%W?-siqCdM%*)x0R617!wIhJF4Ok!{@Myn3xTYguX zZICh{FOG~sO+hdLiHancK#Xj};-3k{4SyGwSogQE#Q&H0Is^ZXuLJaJ`q?7JfHZya z{lhBuGc5S0OYonpW&be1{b^13)#mm$v;0>Kl4Z#3_h{Alb>+eWBd1B@`w`u8ixo)6 zn%pD%n6rjBvIFw+BNKl2BAY#Yn##xmH=^50$CJy!+m`O;<64+7y11dE+p^iz@lwkb z;aEj~+ZGvK%f<*P!@OF+=e@dwj`!_R3Ltu2RVJIFH?rBo_#k--@8yIKIMK(ZFy6oy z+A%8uo%S4&wT}Ap*Fu#uI7Xu+hMH2z-7G5pn1ydy4^j+!M>6K8<%pE z)MWnr&l}iVz|o>(HZ#S~Uc;|#{JwX&yO|)}7A@t_ckc?1@<~JG*Y-gqI^NXT>^W~JN70&UNa#FNauH{t$M3nTJ)mW|``0(kQZox#- zi_0&WoAOoOIydjC1IjMKJcN-{SlYw;UW-|qv9A>tIisZQ)%0{rZ4ou-{?58Zi|q6? z4K73$2r_K=3xvsP%9q;8#S(QxZiAT|O8G3>^F5cYi}J0R#YaWaV~gU}W0ULS?6nu9 z0}Hpp;njk2ANa6%Va+K^yt4YKGEv)dHbL_)2(nhNidc~(AxXlQ<=e3&M=8=_OFMK>7}!=RN#o7;U8JckJiax62C94A7BQq?8E* zWY}T#kgP!?5b=XX5Zb%uo{MinpC-&`vvZC2zsx{jV#oQa9llpvj3_lrwS5 z&Yrka*_#c{EIs+*lkI%!KssOqr&P?^wQ!9M%+mv`qwO5HsUz(tG4|w~50QNvs``56 zPxTfil%8C2FjM zZ}dxpeo>bb#XBDf>qop;y!D@5+JlEi`CV${YX%U#BKK*Zwas;nT8j2q+CHrvGTNDU zwOzR8Z1!n#G6PijPf&1q_fAj#h85NV2Nx_kwJa)3Pr_KkYGY0C&t$&IWMCr z9@qW?GaulyK)-5?dXE`=(I|Rc_qamJsW){&p|MX@+lRDsbg%m#@5yxV2|i_Y^l^b$ z*i$@kNW~-4qwa)$ygM)~WG#-Ttmr%TC@`?@Y|=_8FS|1Rn$E4O?Uz&3>?9hWOXCyQ zI-a``^<*?6ajA=h7P+Op@N1D&vZcg>l&*aO%E@cx^v3=Y%Cpre4;);VuKxT%!u2=S z!KP=|mFr@GMlr>MX3&b>4)-^7T zyP{e6{;YEI^Ye#b5~33MBDWRx@6LRW(?VtCLjSt_O-cwScq%{?>mG&Pkd1WGF#%Lz zHut46!N0y#X4c&KM+q^{_H(XeU|PsI?ZljK3%v_SdBDjf&hB$E512W?KI;T5pFJ6K zt>WIuPbC8@g&tSGesnVDaHvq%*}HG^Vg}#(o*1r3+Sc%VOX+br*p}e8Av^g+$L=rO zsTWslxDn*KYKxNK=t}*#nreyB-qKYoeEu#lUbpc|sNyaE#RubrQw?GRgO&;Gh^=)X zglH|iwJoqIRthBerD|zQ}*_{8Xf=jgjVK;`wwcb zIQg8HSbcIw%37hA#U~&;zsch1 zQCA#XDF2(0IOOcRdwyRZO)Rs;nF7ZnKdv>rkf{Eu!BzXS-e^j`&K~`@ZtI$8QHDzn zzUf}H;P^#wG;J~5_!betr<70fMY&&+`d}1KOv~9UZ@skU)e$w>l=2{T=SqXU)IPeK zhYXxpA+6d(7$j?yQDI+UK3~l>A~(B{492e4q+KnF?+~fiwf(TeKK($h5ML?yih=^f z4gE~5U~HFCGr~Mah-yqKgEe-2!s;gffOo2N6QoPc8&;O!TDrQ0QVEEA?LX8j;9rpL zofCN;`+&!h;2+|je?TinP_%B|q%_eM)<9BSCIUt-48riL2z%+CchoX!3{5O=;;tKW zMdQ?pbIcV;yTFkKx)s6@5zywIZ$Gf4lL%#iI&tM7y$y?TpyR>Q=16On zo0=j>kOS{f{ie`Tcr?+MK2bt(N5|9-s}DUHfeZdn1c17Tb|Wj#(7$w03tZ*KlZg@7 z^g^;NQVA=Ah1zRg5}yQd4(o><(KOEyc4s->K5ekSo0jSvE^%2RIYkW3uMlvW?dSbGH+HC)7L^4MnyBC{06PXWsyoN|{itbr1SaX>GeLau=m(a_v-n{x z(O@$uh-N7R`Rr`Lm;zX_#SbG(=~5_@oTi5z&*_N&%6X=4XnqBpI1PJG2f>`}I0FQP zlH7B1>SG25r@dy0qU(EOB$#$D5eZx%P=6D`F^6ZJBUj9)L`uVGK7o}Ii|s0!^ur6@ z3WuR{u;p^*6yYg`$Huwr*+1qvG)&4MFG)l&Kv4+7oVvK%#R@w!sO+$_w2rjnB3KE< z&MV-Cy}3XfE_zVWoQU##-lPcm3+2q|nXoLTQCMc!*^BTjrE-zv&EIP}Wl{vR(q?4J>sYj$1uw8RSKYSTkDFlycGwrfu28 zqWO+3{k9DlxX;W_OvKc({lQ#u1=O5FBOriPqbCPBc|mQP?G=tUU_2>tT{DGQ3p9Yq zQ_BWimpCPN9*fxQ%)sFZ1Uv97c7T|DqLohBoLz3|L3I3vCErV6Eg zDKeUC1zTH}7W4syvV~sDET&}lk~y>V65DIGbfzN3Tar0G74DTYr(%Kon%`r9w)3it zL(rVr!&5ZbWtE*@MVwy3&M!`Nn#?a&b&}-nNZ3b2c0;;7>N!OEY0J)bLI+B##Sby7 zgt2XzvqDW0#BmJZhpXA}usm5bDyW!CHsG!a;kk?aWUpw80%VGXPnA0Eipr&(-j@LY zdy~z0R*p8(765J519E4|^*OXt)9x} zR=O@znABh3F23(A=IwQyPQ8)HSwCw}|Iy64D4!!nAe777?ewT2k%#v(Lw^c7;Ztob z6SGb$K29i(4UaH6DxnupoklyjDIuEAtY?pRSiD2*W27*tHe++G{mmO~6BacwRn-o6 zDl?SFiam~qJt>bY)V~&g`pKA1IW`9KgKSR-feX|dYhbxX9~AbwZ;)*faER>tu2XHci9}y&`Ox2*mVMQ? z2snA-L(V~@x~^HW`)baHpYE`m>Xh4`hEF?xD9NN$I>roylg?mHUwysT*|6^Og}rK? zT3y)3dK4160{84G9CP7oF$sNhH?6ZG>(%Kjwe0&+LT-_xjfU6aYhf~?x{YB+K&aIo ztZ9K+U+c0dqMRI|VGt17K2DbGW@ZVy;kiPlt1vUSv7G6TJ)N+|tqC`bB_*7bk?fr1 z8a!|<%$#L_R2ZO@%yEdT_RX3kdw{PZjKMyrPW5u`MBsFy8N(#kTxF%n9N)$mpeGCv z(?hO|;u#9uqA-LM^+Q25?>evBCMGcnoa$YE0L9p(G6_knBdZr`^Q6Y;tv zy4e?55v`YQn0PJN#~-5X>eM=p86X8Oy7%3>d+_0)PO6G}4^}}we<<;?W5OHp8a10| z=+<=GA;oU3SofG0VmIaUzz9-B<(BkhYtfp z1@7zC+vSafPhk17&_?>j83iA}KNuis#|g}sgd??`gxHb?rGbG1HF}4j&D45DF-~*A|Wfi zBaqUqlsfu&1g#n0)y)8DN@C;wYd> zp>6d>bx|;+4C)8(LZ1RW2>1eC`tu3wlkL)yR6KG5QbfO zAt>;W9qDH3Bh433M*{T>u&`*H0SXfk!+&lD_#h7oG*Ma?P|@%VV4v@SN7Bn~=V_~) zwC$@2%7C_9*;DW!#Hu{_eY|sx-;)Pwch$phzTe_hNLH;iP}BKl7;}B6&qm*Wy%aQB z5Pd(JiEUTEXJpmyx@n<1AO=DYJD| zkM0wlE$UYgck_=eX}hIC=zhr$JW=?bu7TpB&VX)L^&jfDd&2zkOP99DSB8`qE;^jD zN{1TC0C|29uU|eGXSoGerJ#c@m3Gq50C#mio+ zqlX9}1^h?S6t@Wy3D;$n%1y}l&d*$c!jqCCC7LFYr%<6nk90~Fou|d7? zLTGljVZH=*Dbn`mEOWPMNxs{PNJLq{L^0>CF+kcokVig{kHXstrn3De;?9#uz4IZR z_!ZI}2B`16$2RprlEQ|uT_{yl&zJ6l?WUvd(u+nd+$6@EhZ^Bz?So|Hf@$Mp=@F)P zHI<35PuC$v&@_byc)4`si-(ZsY#?bt07#7kMEwmQV>Xb|3?Pn01uTnx2k8IXqAAz9 zXbtT>Tk)uj{peJSn^j0Xg}=cfq~!1W!3mP}!qYL<3=$isg!xj0ppnp#wvnxa$*vf| z+vGHjK=*4Cwpp}oQ8W=Qpi-nBgb9@JJ3#cgfn1USivS>Ai-1};$}1=YAgCEKu$n0- zJ!vjM{Zg7tB#tz(za!0GA~8h{*hHI80UVK;Wd90?N%jnmW|I9M98Frp4fHG5<|lg& zpm|;6a5Sl->8Q;CG-=WQ-nAKmoT($WAUPKO0ogNwc**_)*X9NS!vCMS#tHwt9C3ht z$F+IG|HnYV{bBKj0fhp^S77jXne0PJkuf1L{*S~|WbYG-n~PQ^*~N99 zJ`bD4%x>LVP0fc_*PHwt_bhb2V4dCVBn#X&`BA^xI%V-F$=u^vFyJmY=)bEaYmF6K zs&x!)Zijg;inY9+$S3-IhZD5CS7m4V-G!Q(T&2kYJ3S$ttQ~2euglKe9H&OI>2@7a z@Eh%#)AuLaHP>u64fJ1qpJfpT=vM=T&#VFB!WuREZ^8L$$6v0vCu1Gv74}XuJ;Tw? zV;%iykbc{i@1a^tqMo&ig!r7zl`wl)_~?K^fx!M-4_^)uDDcJ*VwWsTp`;dNs_W8s zbbUhnfN|=_t^Fy4n*1ulq66y6Rp?i=6|U25^2yF=*)Nd*NCpsuBR z?X~y%zTf%%ajxskYcS>*&zsNv-0$<|(B9nE(cH$GJz~v4fJUtudp5v4aiR z-q83aI{9s4TW(={V|_;(dnFqi%bzI9nb|nnIGEYkk_ZdmqQ*r6)HgJ@zLnjj0Rp)t ztsNZotqqMOMfk{Wa$ztxH{xa$eJaQ)#>6bb%E8IRB+4no^puN}nUzbFU6_kQh)wWk zS`iyVu$8g3BIFq02%_+Js4LQC^P^x8Wao~)O9=H`lg*j zL*2W{{SO}ij{pY+1A7k<2^#rU3=MNz^v}?n5a@ew@Cb-V4*>u;Xea;-0x}{ZG9n!O zZA{pEa8U3FXy_P^l%gh7CJ}K-F{80!RGnjU&89yw3CdS#Q_Q5koe*0UM_H=^3q>`; ztMDZQEJR^LR?1I`*!CGBMsGxYs5q}@0rz2UDvkz&1`q&z{etlF?f*wE|JH3u=RRU6 zyOoD;e?9?jpT>Td{Tcdy@9D1Gf2qs=z0&@Va`wNVp?GSrx{n)|YzgjF0Y%L)K0hi| zG(P{NXiDtP)#)aHB}Dy{44UNbqSUstU8v^SpYqAmVAHl}D%rQ4z*#>7YFpLHH198H z7ng*r67`8$YX}oKHaF0Eo1^)=`IBhHZ7@|Nx%1e4g>=|yS$&IPBn?kYeEYc!!jORG z*w@pAl=p?}!M@pjwVCmO2-e3t4oY#}l!)Qs$3IS#dK zNY0uj99%H30gXcz6W9b+Qsc1(G8^D?^27KnetpJNbEe!al$Eb@eJ_~0zA!i~`kj8b zXj{--+Pwy>yX+i^uP{n@yw~L))xV9k(0g?oiw||D< zGplXrYv_Ru-Ip%nkF_TP#n*sIqU~z{s_8X=rAs$L05?H+9sT?)5>>*PcyUqnFhro$ zZqrNq8c?V`enm8NWg5~#@q&fbub=XGkBTU4U!bY6WQD-Xdu8~l;ToXUkpGP@_1h5P z3yE(g=BRPf8?!Qer1M_xuDYF^*MNIn>6gw|rJq&5xC@-8aDNN`(l<){Gg?!4klht>sPM(XrNMsgr!%i(-dhl2zk~4f#Lw<>Z>00WOD~o&tDK{KKTpcYyZxAzgBBe^WR(V zx4huI2q&r{7!N zpSJtEmbbt5r|o`oK0jLCo%5OdrRDuw=kw27-aoV5Z%ywP+ud^f$-nhbzi|A2?4dr} z|B2H-Q^WIUvT<&92fW-5B1M*`puL73r_#y$ydMo6^8A<@pj+civ7iZbez96 zJ%-;pnBSV-ub%UlYW?V7{^)vC} zf8y`I*yXQ1>~8?Le(yT|SMB`AFypR={k@(41O5j7I>`97hy4`*)PD!SZ4dh!QGOqZ z{7RJHar$#4@>^f_n?L-eo&Sc@-x1}fkNyWE5vKp>Sbt{J{GXit-@2ZkE?V;9#R6q1 z8&y$re_BUn#|Lc%tI?uNbZwl;BNeHBqrO%05y!QithlVLt$=VPb!DU!rq={BTkMWs z`#MM3oI}Hw4yCKvsjN=Y?U6AHCPnF=$*K9^g{6UtU!p{|oPri*_P<=zf8_blldXKD zRf70B-eMfrLet*PqQ0Y$hX<*x4gq(;dlQ*yJpPemX9PX#+_WMTo^Y!KJ%kQ(ip8|Ahg>|aOsZ z7|oW*p}C(PDX5r=_;G`QB_$*zY2`2gA(+~TJ`!(*ad)BXL-+&vb9ew>s+WK)SL*vZ zFC%q+#ck?uVf!}wxfo|~yop^=smj0O_CK2`M+bzScdwT8u{nR`+GN^l=(`+ycZFE- z?Rj`A-Kpz^_J@|m8>K-FqY8tzT1K6NPqhrW1|5cCp7GJSdWDl@O1!>^P)1=J`CWehdF*=Ej(c0NZi1bj-?;!&8`Vn+e;E zkMMEeOsAWTikc~RadOx5BpkZ$ie=;yjiGwK^!O&Yza9jq-A>T4Gx zgIMxX7-qVgbo+_;=@tO72eX__22WH74-5J{RPr9wAh%U1tFG-rv=SA1%Z5Nzv(+Xv z>f#=41a2=<_7mxFISeUxOmfRHql)%SxNV3mtJ52!M!-i864;{_>$Wh2?HrI_S70Xl zH=dkDeBcGmeU0{n@f_vOR$=cw;x5#j=McgbCmABRdumR;}AI-li?$GkdPASV1)6X-32f>mT zH#py$2=I|c(q=HWKi05y7Lz%Gw`yB3rLlFWO87d7cg2jZ(-Z3yuVjEz97uOBpoG9F zI93y0m&@tKgR+d14h(CZ;^Kapj*oM3g)K>0J)^y_$P?wz(HUT~dPU>uMAy8WMmioo zGZtv|*kr;OBij^NWz`1W zvV+x5+`s{3WJ-Kt_6&~Q#ID0nIpe5(Zx!M^{E)#2_p`nHn&Sv1N_@GI7AC>DN;5HP z&(RF#G_hYN=xB4;=~N}%*;;!}7{X_!RLed6#v*ay=`zj0U~7BVjySpfgy;o^FwaBm zK0sJear#;G=A&@K$xyfJ_kNH7Xj0N%!!23vU{M-!w8 zoocmKbI3r6JH5s@k6}8byIacwhiSqmxFqtK(ju_yD|bGyAU!!@Rvt6u9hGaRjSL5Y zD`_Eq6GaX7;6%RxgI>rnN4ZLeWqFksm+Q*bY>A9ru4U6wB`TG9MNsuUdq2pz$ycd& zoGT0E9ccD%oNbGyiq2G3uv}we(`q7Y2P)riqYTcl&_oRjm?mx6Wzt0sE~T{BU|@4_ zfeY3Ut){bW@{^(NvugT?zSOrs$DB~N64|pXD3E=@XUtsGkuTgtU0IxnJnm7W^U}&7 z;8K1jYJ9LThS-wUV|L<9R$+ILkQ}}gxrz-g_SJ$@A531rwxcB8_$X#%)+ijXDP4Vo zrJXGuWrT7$fxSyvwqRyEwkVdI>Q(1)(waqE=*Qz&ytS>Sgnkh7@HiW3l(M>lc6iMu zE3Gq-K!X|j({#XQSO@IZV`(G7FG~?{oxl_vk-QrXZa}@yJ$$$ghQgK$ zD_P(Vl&*pTMHHI~Zi)(8luoa?v+HX#BMUxI679jmO@_(N8#@k%zfv)Hw#B!zR;MKL zX0VIM$9*C&Ff2Gc*vr{9Y2?{Bv>h!eLH&-Ym14e|xw1tu#gl3k$_ldB{Xr*fDOGa( z_?0qXGkPv1y+Jx^*hH-nyIOyVuIVZrv_wEHWUJZEDB>7 zCvU6AxuZPab7-rcvbQ^B#|VDa5ntHFVi!|jS}6fZWSaJ3Iz7=O#+l5xfb4tnc8cwA z;XA~8M6l0RtBRY-GV!1_&KFfLYS-j7Av!Dg>kP_130|CYu~Z23Qz0}JqqeUCMO%vj zn-Cw(=j8{Nnk`q!>zegXx(RfkO0qYv>GV10Bc|2Kr!%-tjU&AYKc^`)slaSogb$N5V_kKmJ^*Bq4*nUAo4) zTeyV%_51ck;?>Pi=_cyU_m8k&Bu=cUTTfc{m~|tf?IKE`u3AnJSh#R0e(mhT_i`^y zZq@?higdS-UUrz)6OVgMJpLrh*@f|a{4n%m{E++K#t%^#dTxT7^;g$`>c^cUjj{Di zBS#M{**&iTx}ZEdQM|&WU1SiMf(;=lSg18_dO8+Yed~~L(mFw$UpfMO-?NcGKCw%= zmu-9`5PXhFS`}dNWC`vK*8bHlp(M=q+O+?5W`;{RnjSD{>Njhzy~i^IKaAS02+Y%CFIylI(16RMg^a}j5>3)<@gSy zC0?L>xdy=_j~E+-ao>4JRd^^+?aP!R*lEUXR{IhAwiKtRDuor*JLw1bX++TAQ5Ev) z0#4-&Yt7_QShB!svYz<&G?0*}!2(WpC7A%jZ(18TonC-;?w#CzZsJXTLe$Gh)s9PY z`AafYTz-kN=!rx{ee+(-1_$8w+(N8I!_+VhIlNv{%~)X}$jK?3?xwG0Za|1^;7O__ zRqpL3v+nlemy%h)=a9{s*!`Nz_*IcqVYk4l1@GJ6LXaTxmCS+ z$}$V$=EPi7w(-HQaq6}=IM0Mmr0ntDfWaurYA(b=j&vp32za51SzC|Gin^o=6*ZaR zXgz2pU|(O7oCu8Zz!1DSleNbngyWD5_Pz#C#O>ho58CZMY992$f+Kr|m+}%Z30n4b z8~Yr$x_Jyp40;S4cyJ4vLsXJYrvOlK(k~s8q~vo zbkSiFABXqY#8@1hISd<)Imdp@ef15)^h+u^zv}k!NkfZQ)9s{Y$~lW?u-z5<>)WrB zsDW(o*jC4&%;p@>mzWs0Dy}~GSj@!9>?colv1#7oz{ze6Gh1ilN2^jW58|OQ8&dH< z<+mDI((O6C3d{#*QcgDbb3=u=&7%Yr9nZGOArW>@2J#}9&TLI%gU|Z^%ODf zd6D|?)mO!g;}?<3+57N;jWMf>-33Pu#fHBuZ9NVNsk3O0eC1QHkT*&FIVm1l zaXpp_9VM;&pf2r$fY*H3$R4xI$DJ@E&PHkHA=+5oYrwE8L6VNxc2xCvPp6#w1E~WL zL@4e{EYbsME0sCpDpdof0TnOC=U^Hw!n%F>TwT|Gp&&Z&nRC7!xOT0OIxYf$@ z$q9v?Z09)_+e8P(E$pSU@lm|llo0O`4}m!iKCVPwAI|}@blxk!vhCUJ3WGFC6Q3q^ zT8k8GHh81JXB~aQkF^Rz>>^`JKn|`b;?42%-ip@ZTnqDVG}zE)-MuG~M%qB{rore0 ze}?{a_UgCVt&&aR@gENfXICCuzE;H^&;@tkAV>JNcja4Y5?F!Mx2;g4=1!dDa@AK4 z@I7$}&ZcY7`)Sbaf5`2jh}6InUFWyr}i4 zuzYXeB*bT37O(}m&tO@($J1on-UF#BpRL6^L^Tf$69dL-&rn*XzeMnTkH1ketFE$E z-7rwQHFxrD4Qox&Ug6=9ibf|Sk1#?BW&OVVTZ4i*K_#TZ28e}5HIFCo8t~Q&ZYY!5 zKreM=!+2{yw<5@k?n5R+NyS)5sFACzB(rX#_M!|^vHrT_GYP!9cZ0JW=zycjZ3&pR zyiY^VJIyx-HJ$5@?|tP!7yQKQc;a`o5?db{))=?agdBo7NN?9-wX@w|aW5M;T zXu0QXl}Sgb)z4bKJ!WC8oG5zqWc_KxNDnqbd|wro(ttbBC%vLC$@_yH(tI?1pC;}$C26a6%A&`^7gOvb3*p@)N4kjxlY!!UC;BHEf;~p?r{7z zx{;8RJ=u>72^{?4n?tLjW5de$t#og+7z$RUm3N(#^h`}Z<}NX@V0UvZq(ePm)X(gj z*5jcAdLdA#A~GDZTX2!aP^*)NHC*md(_XRg1k8Zv-3$dx)0CZX4uCz`{$=s*rnZFc zJVn65?HK%6Y@}xEnejD`{le;Df%;)6VY-JXY1mohXb@WT-oj^MJ3I3>C;rENky`A{ z$1ov|{1l);oQa~D$f#l~so*0o8y#!5xJ~%&(Tq(87OpJSw-+@;b-4BRT3yxLmw}%H zjmgpmGE$_&Hn>d7@^z$xdfIYQs@43M3kxjW8Sf|hfFcHqD)~=Dl*#58AnKyiNnZHx z4JWG&myS5=7|m&+wD2veqeOOl9_Z(hzpBDjn-;=@6!Z$(e*BzWfbkMbSL~jRzuV-2 zV6K(ulQ0kezy-JWl)zxwtFnluinoQMPuOv|)TD6>ZTb(*X_RNcq;vFbbwPFE$}e0v zYN%ru_MgWT*_JGq%Ppwso0&{e;LAr;K_~1~zRn2THz^o>JKzbb)5f$@If`0Vv$v}_ zOZZ@8qy!Z@+A&eXwJQc`FhFnBnNV`r%-J92JsBg40EYIyV6p4X><;iFkN`U8@Jsw=6T3r|?L&<0wyG|9qQjz$t^;*%fZ0+$9LBt32%4lLpFiNz`=t zd}C!jO<=Vz@PV~OXW$9wSSUXG@*$XqC{>ETwWHW*7nt9qW@uos5uY_|%I?7yK=n>s zrnneqCSae4cgLAtsN@6nm^UGMD%Z{4Ge)G2fXA0+jZ4+g%=-Ct%Fv~m$T%EBB_;HJ z%X!{Pl_Ku5kW>yxd2C68R@b8hewF7gwT%hYUxV#R?8=q`s z310)Gb>eK=_o&NGQ|YU-hun5}s+VT=Vy9}V2zJf<&8)x)(I{I=GZUJx3$iL^aAqcw z+iU#GgwvE!-zWh`Joe0^7JAy2tP5Sch`TkN7C!LRRAT0At1)L-aZbz}Po1x^H?gY} zs*5|g=6_vq=1^`h?^|KAleRhn9ecPd*90TimKCv9w-ykmlIpSYTm@Vq9J4$-`qTh> z;b-uvB|zr%q)oc{Rn1XxZg+ii*L39lSc{Q8BJ{Kc0k@Ii2p7RCg8t;)1Wt*~Y?37o zP)2C>%6?9e*2U3GamK7N6P-#44MwN$L}h{^ke zG>uMFNA6WY<~tTT-?X~Scb?=2gm(M9qL|Y!dX*q6p)xI!&F#X#G`_{)wkyMH1LQ~f z@I_a|#K>xVYwrFP6U-Ozl(q5-(D8hU+u~73=d#sO(LhD9!urxU{(8Vyg7BJ)%AA&+ zS+-Bfwrppzb1#3D zvZ45HE;$0t0Tn(x0SA(y3|0${2a@WFH8+41l5?tv_U%0XWW>pYCd}`)_5G7jDwu(li-^2fm3tJ z22}d}mz?K*$5?&nk^776%H`|KM&`bKghpl2k~48lEnIrbwV)D6-zshTKD}qBZ@`|^ z8A=OJMWu@8s#*iWEO;t+rO0D9xF32s@qwUMReeKY(Ff<(;z&MXDUws#;4L6{ipiA& zx48DQ{_JLoLZmxd_dsQ~7|lDhL~Aqn^i2_}hITcZ$qVaM_a~?Adrr#HgpP$YxepT# zO||OG{j_DmF6L9D?bL}v>cZAOv?a}2l2%i`VzR_!hH36F?tv0QGn`vx7|Ge2m)9{! znwYO;bHH4x-{h$0o06M^Gf^rE-==Q}Bv+jXh%68Txe2*as`yMZQYhxnt1{wJas=~R z>xLx0mKYzd?3@FyB9)$M?ecg#%stnRkKUjqXPg!(Opg>fZ?!edO;T4~n*x8+p}hut zMmpx44V#DNxxe^K|7o=k#kkvR&4bPN9gmj;lMd-1Br8Tdpulh)lctoymn%y%Q9&`` znL8C$(LUpJo7F?d;`%$O4r6xdMt5y^;S77df)E9jCoe&W57z^day_6oAuajkbN9)4_q5dyP2O0 z47KLg*hXKs?+_fPWpmss^q4fN)B+~F?4Bro*W2&0f6}pIRlFnGaiGohVmcbPi2qPV zJ0o8ena#6uvZa(^q9Wgv>686~NXLuZr(!!!@l-sVpHar;W@sr|Jz5y7TL*J_dG1Sl zkLb-iL9nR&hD+t^X7a6|Ox?}ldn6Z@XpNUOeV-i%wANRojr-`PQZ;cqS;Wvn&{?rX8yf9@lfzx&XF4KI_e9byHpE*0C}h${+FB|Arw z=u8Jnr*95QRTVl?s*x%cJr@(#91qEGtFpKTs6$%T=~OR-(zxgNhOaWO@~1;#S3;PW zikYtl<~`3JP7sIL!pwX=I9ZARMi+Y~8o9=w;njn(ezkolpl8_A=qh=thVasVbw6j( z%~`@;d{kU-&K)mRECf^rHp;=DrY4{5lVUZ@HI(@nW(%juqJnLa$|;Gpn^>z24t_I6 z8k+RT(qPh_$NzOuR5dWT`xvHN8AXfV;juz)&qyUnES(xu{EWQ1U)>t#3&ohe<;N@e zWs8G!gu(zJIBX*j%vPUb87*rjE-u<2?fB{@FJ*iPRjWS9x5y=a zJQ>uJ;S{Y_qk#*Q$XPX>EgbDD=H=DZp?NmAxZD=qM&u;M9n^*o zqafWBW(;He))nVWA8|eWEmZ^6zA>}1W>#WUa4^y_w7O5qPHemhKZ-qDVL*%%){I)t zY!VOoOmKBC%yjQ=;Tc=5Rl$Pm+PJCF2HrWXc}vjy;`#P$P`5Nz-M=TfLB z)}OW6#Mv)-OEO4Q5F?R=$V4j8Ywx-R+CNE{Vi!|QD`*Mb6V$A3Dp3)1w4o`^DSD~) zf%klW;DyI2k&QTYr=hbS3(*J81MX(HI?Uo&*QTnpvJMTb^af1jhE`*#jHBLm9^l-D zP&T2u7(1dWW(@PLOrknMj5I3{ zi}4YVVz{^N>5dEJ*q*Dm+!Zj0@oK8g4t%4W9;qh$?;Ssy%@J&e? z`+Ty2DoBr~-a9JGUkX{;?VmXi4%Bx(v5F@MtU#AE@z@o!mmEKrkrbH9^%i0az{X8C z^u%M<@{I6KTtykKl1r-*QU;C9DW@zz3NN+}uF~->V~mnrjBq>XwbG2Vmg+K*61uBp ze5?&9w~xlisT&(xFrw-|YaPyf9S%)8m_T8IFAlZd(N>q(OYAe~&r_v5_vp%~YjABI zE!3jhvD8+qcx03#l|wrW{W7mti14*Eovo#Pbw#87XB9IkQ&>Kd=b)#oU$k3w=NmXQ z3l}PDKsJGs;C;az`u0{%f4j$P%TL20?1tWjMs99jo@dL%El`cLuDa4E>FlU`PVyKT z9DdfF$}}RHQq|+83+w90<9|Y(y>eW~8>&7%ZafFF%kXuB!6@}xAyx%CqSiIoF!pl$ z;hm6Z)2)G?S%p~dOO>!w>?|H_5r8LASs%f5)|ANQ8# zQlmx>+BNm<&wbXcf6~PuAs5vovkoR1402{!4$fXwvT?n@#wZoOpHExVOQd@qvV+1Xn3&}1sxj< zLT2I~Wa9`)!b~z>#s9cPmV*4|Fr`FR+FP&LYw*aGVe4?_yx6k;xLGWCFK0!EU%oh- z8mMXUZB)`gJucS7aMgW&FT7jdbXKyr#jk^%_-w|qTW6%%+(|AyZd*c`cqSzZCCBw2 zp8WP#%ew|7g-Cs?Q1z-vc}Y;hu6lf2 z1-e?YBtN=`+n03;k)nIxmsNQH04o6HC4d_M|ML0p3fJwij@wDYk8>AylZKn=!0ic) z-^905gg;{a5_TuNn|yq~@!&l_iTQ9A&)6eXyP^8>X5Ihd4RO4H(*rQDN@G*if74Q+ z5(GbXq+~AB5@{7jUHukb*>&R6K<4D(5tk?IsS-C~R-HoY#n#6FL%1%AA`I%GN9GZB zi@{#!D(b-EdKX>@)0UOvJi8f!ir##1$n?g;)GrPeYT{RJZ3ToLH_OErp!6vPL?kh^ zYd|g^+dSy$=fsdzyZX^pg&vbu^DCVdA^pY+Rid%E!QncJ3Z;p&7Tk6nwTDAB~DWTumOvhw(Pexj&}{=2s_LQd2}uJ)zU|IxeCUniM$N)3Okc zOy}V(lIGtfV)SVQ`8M91f@Zqd>;Y2p7*vUOK&%_NGX-ahim;50DyG;fAhferb^0-u zb)PajnS!Tif+NG)1&(|p>}r*lIEegn$PMO#;EGla7ZK_M6168(^(fUrwCw1wMJP?_ z7^`<*Me9$I=xVob@-`HVRaCcrEN>@yIEb?kHCVJJxtJc?)%F0)wvzy>< z*U|2lG+;m>;^XYDc6F!S+fCeGHStHD<6%=iY8SV5ba}d-rXkFpC6A$io9Co$7j5qpx zzfVvqa69c4O=ocI%ghEkJ!Hb`10O*EQpu?P zQN9Yiq*1<#=?VyNMqS-C7^KX3JT^sbG{c0rvT2)w@Ohse3VwPhGF>q7kp?qhk2xP_ z5vxq`bwJUS{_L6}d*GWl25&62+~BlDRk?w<>|`!XgAR%Jwr+k0u|e)mPBstuKy~zB zlF2X)iH%w@BM&LFy#V^vFaUs|kO1n+Qmvl`A_Z!BsD_gCvt( z)^=u=wvafnYm+t=r#`2$7YSs$Uo9&{r4Y;6Y8PbM)!WmaJ8)=OUg+6BCm&E;+%dlg z`#^mrJ|v+6y-Ptd*?*nO(0?7Cj^yLs+{{_%%-%J?)MT&0D-%fN;EvSr3cga?|B^iYMM6j0tcl8Fb{rG|hMHFv5U z8Ily<45~}6M~&@BnL{3!s)#?BOte9avjK(2sW<=uZq4>cTyIB7Z6Z+~jc4|Y|jOVoqf#cDo-NxT2G=3&bWY%;$| zBndd1b!Fkj2PNJKyrsnw^BLoudI!m(5(x_W- zQ+PXS!F-CyT=nykEkY(mQ?*dYHqcbZP%_3#0BDXZS|~=Um=bO66cHI+In$A$Ch1RA zfJ=>%=maW`FISA49<-%fGgfy_;)@{&8Gy{I#q7=jdm6Nz*k6|KWIjZMmt+_m=-F#r z-myIP_FWhpn8oX6OJt*VEqtly)PR8RI4lEl+(LK|TU-Bcl~nSz3>HPqAqz*BFlHl|EIBaW4HNFMn*K6feYuSfw#2(d8_at*(`92$rc) zTiYVspzG64jSoAi@_z;1-%(kq66Vrt5DQ%0IR@aJ0)W=SQL9|y{O;gMIYxIhqRui9 z{ZP(=BffW?(2`P^#3o84Ys5+_agIrm6IU>Pp7F+k6_4*83r#W25wpsfx;s9FNsMVI z>7(QClkS%LcCL6ev;8vB;`(iPj^?LqG(7I6f@sVf|1P zaO4nxS~5ze!t((ZEL8IDLol98e_&ZY33L^Y3ikte5%PE3s1G-(go<0zi_elNs;Dw5 zLmDJU@h&f_YK@6TWE0RHlUY1yh;{i5t5A z*|w<%Mc4Nc*nho$-|^M`?>oLZ?py*e>Y=Pv5!PfakHqD7L#eqa2B~;Uj8m%v0?kZI zCatH7v$BcEX6juzv`vx1nGLC#>{3a1Aqvqu;1D$I^#)?-yiXOxahVDpircvvY<}5h zLH#cb3cS_hzIDhU8n^)v`KUUrFq71!Wd;I}v0>gPbW7zJuN)flIfmNdxgNC|cUAlP z(1+N5U?`2%_c$6T7SfGj?9`_qDUlpx;wL2N3DAC2|LpN^xA<7)PlZCl4ocBpww=r5@dJrv7K z-{G+{N_K2)1ioMpvv*VAMn@-%jHfa8cP`2_SYC-Ib4DfZ?&ej-3W{eHWFb^m=2DdL z83ZO7!VtzxNgY&0E6TCmI6iKu{H=Tns1<6-0kmDcXzxJ}zyrx^K&fn#w3R$n^whTc zPET1)@jwx9J5oN&+{}TLU|IjQ+fF3cdlpc$zZoP;V!Ah8rH4>xg@PtH#Od4mnCPPD zHbFEW4pJ)!5k3zykAC$;8MgW*ZqUPtvjRa#&r!2!Osita>pl}@-Lv?YcoEdhC{E}D zXoPx2{i14m#ZUQJ`t!FC=t5o+Z&Z06`OcfQwcn3t|2S2AcV7F~ zL)*87>vaKGpVaLzx_wd^V4z2<3fw1md6|P+O zJ{1TL0DcNt(GCg*R(G*)w*FaRDs3KK16r;D2*cvd5RS+&U8F4DVT@m;i5!uocT((1 ze$s1z*A-e?s3*G(wO%u(gligMrisdu`Yt^4`(9C2jC}ib0}cH*Z(buzpBSzf$43>eB}*36ms_W+(gZ0l z8N3ZJi+H@iwL?tRbGU1mW=l~98w%S*%}EhAh3jRq&+qZpBD9+mYWM5;gL=>Fx^>CM6UKJCT0P&&4PIrk9FNL^-$-u{7+90Cy?%wDwnpf|(rW375;w_M0vR_lbnYeOKc5s$kjcsMt zT4dU2cV#C<$Umo$PxU8owh$|jkDnXWW!VUxu}7YX9J?a!!K;a;PzLi_GIPl|h6T zTGf)vTWicud3Yd8HV}BCC^?$)LQ8su1fQee_`>!2cr{C!<0@yy;thf-d)33Cczvv6 zx);W0?B3%X#_CHuRiI9YP_I~n8@7@%a`{0Ne*K36j#!c`=PlOD263gz!Zlqnw$~Zx z*#_=*<53TMD596SM+mM?*?k96D|!6<+PH9znffe^>yj8>pP2Smf5RtcNYMF;>ayR8 z(^XtK5fiuVUnP8&9PYk2ps7tzJUfm#*{0lIYd6_E4_?M5F=80Dtb$Yxyi7igLa9o7 z#)?0pW@CUibDS~7Wtz9u1f`Qb%@Fh88sOmL>6EUrN@_@tQrTIrLc3Ru%NCoGT%x)% z^}-*w{WMv?I%3Tu!H4uUp}Ll)cBc znL3$7D9X(*xpv=&2s1=yG}klFcp4W!X7yZ1h8_mP(l{EZW+M3)?p4Ud+pUChNZ|JR zw1x1_fHXr2HC9R2=nJdvHAvea>m=!@NVQP1KyRr`I8y~}ne4r%JS)N3SzX}6Q&o4; zd4kJ@h0KN5P}gs;`Ve|2Jox2XEfN^f@=Qfv@{J%%@B{+2W|&~8wHTi=UTMi{slAyl z(wVdARFkql&ww*BjQI#mMlxyyH$T^Ia%jPcAG-F~`Te64U}iCg5xsA=9csy{q1oQ) zU}?h~DDu(j63N4g((v@5DLirMb>;R11!RFuC4YR_#~X_t^ZmRs?Hwj{vGqeSH7EQw z;75i<`~XFL%EM^lXIA+=AM|LOQjvqj#Dv)LXF@MU;?~0?_GnvZ7pJT1>nJ69?q@qu z`sWUwJfX7O*S3stvk~i6WM9E79@9daO^o^C(oQpKGw{MUcl&s9k2%P*z$r-Mt$LDd zj@YUsTmeJERy?^Aq0*Uqhk55ZmmB99vY&Vy9;%O$k^S^Z1kUSP^*}us?L}cfIb=El z9Q{HWI{NKcBNKA3_1&lTyK^fylVtTxLHY*SrCQ)Z*g<3^4dDU0j*jIyhJ`hGyS>ws zLGuKC@?J~h=WZbK`_}+S(OaRNXq8NY&2}mw0v{(W+}83CcWd05YD|w5AhrGBd?yu~ z)QY?@7peMJt1PTivsPTBdnn)sRVK}F;wc=2+I^K9c4ssCiaAqxlh_sKubx|Gf3|jF zOU8BH<^$*V7V#+;4swxVII!sYM%yNM@+E*Iy4YRvF}6Bc#%TjhaV}dIj^ZYkj$Apx zpc!S)w``v_i4QtLyvBR-^mCW3gg zRo@Q#Ec`FGyU?2esGC@Kp*Kr#f5y6b`RnyP+HJz{?{j949~)k?&UbU>C%8NVA0igJ!-7&A8MvANvNi5%Iuvf z^%|>R@Y8G%NZHyGh~lEHuaZskOH0o?nQZPi*EInjv7`9c05j7@RSfn(brbswvl#j8 zHu$=(SCglkb5--)gd$6etP`jv62iT^FZd^IMx*y@Dit`m2TLpX{b(j=Hz*AA^GzY; z5<5A{%u4+VYeG>oU23(1oY|hqE3}m`6i{oy9Ih16M~(cF6eV9NB3P*i5@|Tk2&Xr6 zDYjMfpl;SF(*XQW0esZ!ZP}YxJC=MG6J7O9F~>S>^nzNZ5WHrcA+)zs)UNn%x2BFD zJr!qF%f9M0Ci(8kibh+fz@$|Txs~}DR)&6G?pSRYj5KX&l=?j=@RW8FFCjHPYyGQW z>)?>gXSoHhmWF9I;hG%BfNoz*w6e9?3azY>Ep{PRh7Y%!dq*=ZaCa>~>T+A3?~{ltE;rDBIFf_a0NzU!dOL-u|c?Kc3k7h{T%4Txu&wHO8s8 zog>;DJ=66w29i{UOJ`(BgiQn_C?m0>S2l<~=RwC~je%f|d!VX4R)EcduF>4dXN`&D zisJgIRbuL_6+O*rr&$3LfVSHnRL4t(W&pi%g5_y>L7K$7(#I8wlR{M zV2HtD{}|0hP8roU>o!?=_zvHj2&0d?(dzZ4-0B>18#2D^ED^Dss}GBwgg|n5zGiP# zy~G2wy?chYi7J>s_8zRBT^+bPQVbi`ZZTV{t$0%S2xJ^Dj z?x$Qf86qrkToINQ8On)J3}+S-Tw*?AFs49I1xD?V)ky~t@(9DW z3EMGn{N##7#(fPa?|x&Z?6|s7*)nL!y}B)XJW*wAWZ2LKp{tKP7Ov&?wKAf?BM_-u zpNJU?%6?QnshF)c9v(Pl^IR_{GoGAWF_9;}3P`6eF^0;lf_xS%9V_if{cY=FVhaly ztNnhBS~Vy4!~K+{54w(9moePs-`-QhD&mqps!`VF>rIB_;lWgaKRsX; z8!*9Tw;o6)QqL57OECjc8Kl`{x153Pjd(DZ79EvO=1qfrj}$rRQFbR&kfWY)S#f=5 z^}+xMU6NWsa$AyOTar(bAA=G+r3_LQRLKV1gLwwP1KeEj&)@|)F6jBi2ftWJ588Es zzJ!+T4SMq0jp!e7JGT|+IQUmJicg=dr8h+eNsBoObUi0=V(Y)i~fZHEgJGFclb=@S}`haqijB4_b*l;c~%TdiE zH2KqZY|>KIx0|AFR!Xpl$u~T>vp1evd7+*0)p36>>NX9-)NPvBKhrE*+1x~_{gH+} zdxP^XP3_i7$RD-QE?VaAsv*2nivLb2-@9x=QaCqD&k1>!CK$Qe?lkX`xDgQF3EJ

UxuTlUM1+ID}{;Jf17E-M*rs~!h_N{t&BAeS2eyPgw#S8DdBQh(rggR<@H;thUw zV_o0%{9b45iyI|=)EWO4!8^E8&u-y5zk}<0VFG)<=v8v77vo)FA$JHa|5f?#8T~7Q zzpCCodkxr4HJtlZ*705Y?{&<*wFPIQ=B<@~RTld@X8)vo$6spw7i;)u-m>lw(Eeb; zAE5m~x?jw3!$QUr_wRx`^8POPGs#b!Z*}-L@cdxvuQ+#H{nXR(z<0cH3AZ$un~q@#+Qk;=SQRk z0wf>dD-Sldx>&xbGVTUa_j-z410o0qF2|Q&yz7c|If~paMT5e4J=5d7BH%E2_*TTp zUi-_?{Ar^B8evlG3zpA(HaKs@O({PFT@Gn>lA`_p5&sI$^ASa_*VxpK!|knQkx_-p zq(M5VYkIkT#~*VB`On-~M!uAzalN|T@V&kMx^@Wp_rDg&@uIsVF#QUA{te`Ul&^o>{MK zbo=Igd;OAVs3kR*U}(v*rJO#M<`m;f!kOc)h_Iu;!r zDH4}OEr(OCPU#xpF*AsyYs$yjW&8>*w+%hcav^R#4?>;DVy1n}aL!V=SW&XNFhQwa6|-<^mD( z3rq(?hV(UgQWS`>r}ye+K|&lit)n3lm8B`sAWM*SCcL&tBp*SB+?K4#>_>K3LrrW# zYdO6ChqkwlYWna0hp`0&m2Q-7B{oV>KtSo*h%q`hMsKu5Nq2|Ru#IM;1nC$hu>m8b zrIA!b{oGvl_d4gkuRp%$I=?@D|G&?9pLf1q&qu0y1OQftfr}XpYPB^lt@)hNFul6C zsj8y!Y>1_{xuF!zdej4FD*UE5I6z;Ht%+6HcP1vWEur{EKB79+jFdjZw0;exXbxqn zyTzq9PR{PGcycs3vNMQ}LsZ|mUw4~bRg|rpZRmA7BRibdxQMQ+>Py9kO6ah5`uu!K z%TZC0eV*Y?4%Nkr^qJ;7;aZn`X6n281W4$IW5T^J()wyJ&>`QEN zYy}vzHG)^{KaeCof~g9qn*eW%%vTStc-jBi0IP%2mFODkwkv?r{(!IE{Ge^N9jGW2 zZACZ(N4P=i#+oYFpDEPOh~SCphST%L_N^}JNbtVez4D*!N9%0~W((pV8owgJACgGD zrntEvyphDZb;U}Ic7_k&J*nmne~yxue`{+r_T>PbP=rku87D!tIVAEtqR881%Dc|{ ziWM)_8u~)hsA?0Rhs$f7Ktsh_Mwa2G(7-%?9k>KbgYk6Ah(;jn!5adW9$a&i%4%|! zXLER%@}Yry@>$1XB|O`L*AxEB@q<^;k?RXnsL9qqlCY>xTI}+v?3Sfb9EA>t%{#qrce7_T;=|5h1djSy8}O_FV`E0cJFSF0N=&$; zxxZ$j9dT8hv*HG_UabMaxPvjrP#C_nUFT}m!G8F4P$M;hu^Qc^bPCR@-u=aej-MD; zq@_ZAw#k|W$>*Gcz1oR<(oAk5gGLzdyKB={g0#FfbJwMA5yA#~#Dn?({-R_@Ym}}V z7F=uAjc%!5ac%wDLGg-j0*wbky>-isIXWC$1|h5Pw;H76nm z>yWHl%Aj7vQ!ANfTE9DNSe7@qy6Oe+Zu+VONnc<{%*)H%gRSxJ%a&-X6!zDRK-C{Y z)uchIQE^u^|L(HrrJrHU2o9(QJ=SKu7jG z@`)+`fbA8s{b8!okM;sH6a3kO5@+cC@ZF>)1gGEq3bxERD-Cg3GcAX;#Rj4o7(rt6 zLzvy=2N~pPZTEzO#C+48Um(gk4=MnEm#|VPaqngTm+3Y4Cn*JDa|56@J-1)AQ+}r|IIEQhXb(XvD;TIS6snSBmxwg0(d1- zT-eRsYHv^7Z^5uNeo3I(S8Ld$gi?YO-aZ)C(dg)}78U!}v^rI0A*B{UFk)Y=bVVjau8K0?$%lECR(BP zD#|}IK>nOMDk5SyLqQ}CV86olQ~$lc&O5Q3{i=yE9XO3l=qCT7@{frv2Ifw-M#DyL zO=m$+JHz08-{uVC>k_)jC9(DgCwIGE)ji!gp8Da}=He&Xnnyag#XR6An>;ea(FX;J z5+h&q1D4Mc3TD_vh;>~`BPNo3*QU2DH8He7q7iG}^kW_1WD$t7l>~8U&8?E?Fg$pFu3>gCtKPVp)OFpnon@U*2mdm^lqT0_@%&Y zs=7Sh^xe>bKI`HuY2H@3JD8LVh~lb!{Y7~DsTxTAa~)^uhpZ>zZDR)jdErPD=TL?V z|GiDlj_+wkNQAQcn}NOk3#{O)uz0xCIP6_bG8b8!QBdwBB{H>ZxMfD#eSTpyg?5Zn z_0%ULYp_1QRN-^h`Pi@Dr%K`fP#9Qpd;9W6~t#;-R#6jC1+$^0K1pFm7^4#aY{3tNTD9~XoQ%j*M3jbgCi*hhdVDC z6M?X?#_A5T=BqUoU&O{wJxt@Zm)n;ZqRx_9ThPmI)Lh~&yYvEF%Kr=-{VYa*gBGm- zty!Rz$gw+rof>7|6{XbIGI5{D?oYifErzcq_y!F$7sb0NYCafhGM#J?d5Wutl3(j3 z%Sv2eE=6E4%?$*HamapRNympQAg+2iTMOqjqoe@;#YJ*B;wx>mO)i-M}%s5Hp{zzYM&2nGW;< zHWvH!MQdhD_W<87xvU?0bsE6g>0*b}sNMH;N?qG{m91GVM)c@CVcI%M2`9N1+r{eI zmuSzZSEzm2LBhl(0d@I^W3BckzjEXsAEy1#7T74olAJBI5&B4Iz>ORFcE6`g#T2#` zSXZZ;|7--~J9HG|y@i~xE|$XI>00(Fes^gkD@1-phVP%H8%e*A#T1V|THH z+)T4qC1oV57%H^o=f8X8X497Qx^41<^RcGSKNOcQ_rar`&ut;&-{k*3q9-oiuhf~{~MPMnVY(ajVa&7aZ4B0 zKAl*4$r(~vJtyOI-WzwF^@XivEvjB#X6{qht=;J%$M~V^kUHZTSyTDVv9H{v=lZ`A zPT4!Zn?W}>f`K*NanM0t}Wv`!b#+BT>Yyiq!<6O({WgyF0&U#eX-K15!EKk|BS)$QW`UmYtBb_V{w=m~}VQ{K@m7 z{?UGXTC~@K*FM1>?-Q2s9CNQsQp%gL%T@SNaxkXSqCk`2%qhqHN%8X{Eqj|K@Tq^$ z=Ril#X5>NX`W>d8sW)3qS3wO#h%T$IBmWD*jR5~<7WunT=_OKd1*ts1tsdX=qK$;i zK(6{a&YtQ26&L=mfN~TU`85f4a2`$kn^=Aa98~Z}^N-QLyc++fa4 zo!Y#Cq(7?mWgkoZfA!~bD{%^RsrN6j$zMO1Fnn?u<~4_;pOK8elk={0>A&$v4h(QJT`C`jr0 zyprXe`g2tK$9K!sr(v4kwd&5`sO>)YEZTKQy`#%?!iSf2!jfUc6wHk19`Dz+nTs7i z{;V#iv9E)kmrirqn|+cBNyjpw%jubj!6$`?D+KKWk-1&nz21ww57s+-iP+cNb}K+q z0vrn%3DFFT7(K_4Oxp6lqGltaK+d`;psJ7(cOQYlb}Mcw{-TcDOUq!w8h!1?qspY* z#BQb>2KWB*hsp=@Yx9)wfh#DZ!sY-^v0Lm6XSqmzs6l|h1x8FgUHZz$>%s+3lE9Up zeWa!B8UD(+nJPYgk#uPeMzFdNIU?`~_RB;B+;5!vCyB12%;~ESuRzpA9nQ9red;Y{ za!U9JLG|_=8l`;-Mp87%ZS&v`xr{dIIIE}hNT!L(@}LhKU!ttO7;Zy=Yb6A17-JObtpK&65q=UIxp>+egY7)4otm)44a>l{u*4mi_W` z9KMddZmlUd$M=%nuawWsk{6xU-3Zq<1>I@@?3f`4wBNWx%x2}43eKl(^NfIz-*PJ2 zvn}sZ#o#oqGzf8P%aFMqn9p-e4Dl9J!+ z{9N09kTNR}wy=kdX;XQs$Gu~6S(estW~@0*YV`HZF4rTJ=;=1UqhSL{N+C$A(2=aq~hC92Cdb5maPP%^NbQo31Fnx zQXg9LRuzdBEz3XnWZoQH#+#JZUo>f@DQq);DFZvSz%@CDq~9KObLwN1BtjLPz~ygz z<(^I_r;v|z&+@Qy68OUPeObQmuh=FhS&_sNow{!dCU>Q2lGz`?I`68LRlRG0? z7^|~;XV@akQwSr=@&!v>xLzW5DOo&=*$+Y+dx?qF6Mo#r33Y6toVY-&s7J-(!SD+s z+UZ~jrH&(Ly0#cRile~d&Xp+PEM!hY48Dc@A>H^#bRd#5bYSPzP@@Xm!(++uE7)!U zZbswyA}sGibRyDBDZ(&KojHDZc6&HcahM+0Z}5jxP`rELABqC0CJrfywIi=)YL;t- zv9Z(b<66>tMEG5(Q{Qd2j(r)`7SwNd#M58x`S6DpxeAqCSf+!^Q;LJVJh${ct6JOWjvN^XPb>;Mtm#AThhG0Nf3hCE^*3xX< zJ@@50Ux&0ODAWCo5>x&@&5+S)ut$*mWvUh{%ejeLulHOK@Hob;iH@wq%g@enhKump zn1gC2Iz=c-9m-{vZ(u}5;O^FUUGnnDEi^`>y^VSCguC#Me9Uw|z8^rXPam-%C0b?) zWd~gq);=8DO2WbVWsr#BsiN#WS^6+tzV+jm6;1Z{Gp_d;nTplfv8)a1=Iy47&s3(L z_i5R!mNdHUUci&1CoWL_ns8X_=~4XN@HIMt${_6pMjjypD zP_CNRZ#$2gGe12=`ZJGu^>`(im(=%Ofi?1zKJ#9YcGH#;20nC#Yr5((=1=`iT2_J` za(-R;`Ik4b?)Q9w!QTEYPYeoMQL*ESy%$%o$y_9P8UZwPDqDg2hSmhn9+MC zgd0z!uOF^Rbk|O+g1ic;4CTMw81k;8f4Oai(6ax1ZLP}KA%7m{=gwCLuXNxFe__~M|H0nv_0mt)-I{#?e$9yFRk#tjiSHQF<0qNiyQ3j; z^M`5u{Ztd>e<-4MtlxE5zPcu{b08XzTgaBNksx1jWMisTgRj2{rg*copP>@!A3QlH zn0;uWmVYk>V?OL^B6VA6y2Uic=uvGyY_m-Az3-7;EpcnBAHsX#*X^}H`iJ6Vjys_` zyqdX1x2NipVUK}GLB;$GBD`LgKv{8kp`^VXj#SVeZDw}*WxFTOf86`++n=)VP!};K z_>%HH@=t{wVRK*pWw|4WE)843B|Jx`WmwZP8C1EkdwRmcXEWh-*53`^3~$l$3ful z?N@QixSzM|7nVbo0va8pPqyaV=E#UiPv|1}kJ9uR@Z4x^#-dkPBS}SM#mI0bRDN~G zidgZk>ea?hUyUAsL91RpsEAKOq2%Eg*`pTiTeG+-nrS8dsRFDH;yHVt zsPsZJ!pkg!0lgv^b7xA63X@%ks&0_%qi?T(zZ<^6n$`iVR-UrfpSD{XGi*cj_HGvE z=`BxIwXj997mBBqh@!II>q5O zph4eYeXriEE5SWKk$@hQZykT8x7}$v=i9q$!}jJi&cOR>ue|` zIXXQdmsLPi)XM^z+EZ4^*KEtu)%*9sc9$G8^GweT-H#Teust3%o7yu>N z+mmAIM1q+?lay1Rmc!xn*wO2$AAc9~YyP|lBWm2%R$a2;-MdT;)qQd#hmrRKw)!!zs9jM)_R;&7($@hnPCI8eyZ zKp(1srJR%aD;ay4ma6bCYghkb-&3YrKkiW64DEa>*YQ8jtbb$m|5XV59|zDWHC%Q( z5XX)gF@GK!u(QwZm$K6C=dW6P4oJcsH6xOt7yZ57CBFagm(hDhiz48uyL}N7Q1NFG5Ne(6&Ssg zP_vHueE4^s>~FJk&v-peZ7A8bg%=dvgCbj7e`gfdxuNHAG-RqFuE8lVO5PDf z4A0l=^F+znmG}aET}BK471$@hD;-j5S}8+*zK|>;wQwmuvCs{fOD+*~8Uf482Ql$L zzHvG$Pxgs`rZ@kgxG!zb%a4S3)=b3?8Qt=}@{pnCnc3DyVy4j4sbFafYo3?4HPi4^ zi^gctHMm?%ySV7_l%M1nZs*vnj4!lS}#~fGC1H1kEM{Mykc?x|iBjA*3jlse4 zvDU}?*t2I*$**`TVpnPD`>2AECIWY&%h4qk<~6XjD|&r9;?J%L+rVrpn@#dsl4WR$ z{MBwaI+yV8FIB2&$<_&(IT-lIZ1w7Y!#%u6I;jP#mW21lftz2F)pJJ;l zQeTy{L&}L^zxH!ZqO*7>!l9}mA#m#xaob7z3JJnakZHbEDrD9Mz`$TFrS@w@qHi?VTYuuwAapED;bO-0=;50 z+mzg^d=ebm++%%DoWIB3dgjadeCuB817~*2x8>8&yCZDB7oNNZ!uY;jey@_OIeSuV zuB8)#Vo8Rmy)f6K3DN!eG+{+~bZv1)t=+?RFA{R^iCqcwRl*@XP)f=a)QE~GcCttb zN~EMJNxNcS8Va^4GM>uM-t--9YJL>s1OtDgEmQZS(ke11(|tIq;&rZ(Fj8{FPT&i0bsb6fu;Sec7S3M<-_u zKDK9xUVefznYO_PrZH4*R8q44pm?bWm}f5dQo|k*f2DHAZ-&qp{JbxS>V5_^{;iqh z)iM*r5~o4(s*CdG&B^&J(L2Ug|KFSP|0Z2t<+m&P>n$&OGy?rQ8h9tr{pcSG-|tV~ zx&1>yzvfK%WA!S-@8Cx@_g{+TA9RJ|V@&MR!68=;QswB}%Oy9Gc z`AO)hejK61Q=j5oAS_+YGhx&(k|brxE?)D=UWV>zeJD$`Z^&|ed{}^nDl+|zThISJ zIyC|DbO+$~yBGEk#S4?0qEC4Ly&$lx{O5x3Z;BrB9~3?DKPdW6&Mmiwar9zlj-$Yk zl0ifFu9aLhy**a@^V{4wb2Ei&>al%b@ov)*?^gBEE-t|%cp_To~Y^xTgSwI4xm zD;tD<{}3v^$8yhS&cNiv_RpfNw= zx4*n`Sedpk2Rsr!b;9)hUDGAE4KB*LlUnbOG`ecFB-*-F)`z7aUKM5Wc`nA-ycEWL zaWU(X)q4`IU%T0<2a;*l-mZ^4;JQ~BUKZWcH(2)kMwINFu_>IZ5xnzkPrabkYNFHD z#y~K+Z!Ls>p-SR%U~s8Mj|<4jRv zF{Y|YZXe5HT>DW<_6CVp-;H$(!@jMIpIW7H<5feLE#cGJ*9={hwZ+|(JpA2C<265h z`q|&#n$-E3o~tB~n1MKp#t!&SYD-kI8#=yyGk%Q*{qbcG;kdztJ3C%&>>El=HTL%|@V`H^I@?x~lzk)l2 zoqBZB$Z4)P*52?BE?;KQoA*Mo3(YbMbI_shUyaqg{gVI8wl{K?{hFD1N=hZ5Dw3Ot z)N)z&)|ymKT$nq{PO!XC6A0QYJfmyCS(GQ~FoAo-{eULdzp$X+-m7^uZL4Zkw<(;a za=g-mFTz=&DM)3@K6LG8l^r&J_XxV(c=yga+A9VWl6{6mHS@~~O@bYnU53}=hM=yf zlj|%3&L-A$;V04RMTA!%{`=kObxd(Qol4zu$>T@Wr^yg?9}9sA5ue7Jm7LE7xdv~! zOQkSHH!Jw>XHbd9${a<0vDBB{_!;?>H$7NZphU>ED3Rq&^q;PoQ?mKOGa~V3Ub46` z(SB`7R;lN(KcPd$TdwIKQCCa5trDU9j2H1x>kKPm0+eS@NFjmN_*;frn98QN^qWB; zbBXf?CA*3taD5MvX)fPA%00aBR6R7tr|#1bpyW}tC9{AdhxZdFun@B5tyfxHyk$7@ zFe`Wzaf>To`dXr|tTn`XHv7wrFglT10TrlJ5~RqEB7XLMYpOo~tDXyv?6l1`wnD2uz++7k#fh9rSH;bU-r}!Tj)qwE%qbScCBU{he|Gf(v}aLN zF{ETRa-oU2*^Zvwl+Je`#*W$nf9t(7)ew*Bed{%57S3a1YvvKZ=v))M-p4io@KDqt97|!zE4Wr^c5$z|TDT(*YEM;BbAd?F0 ze8*K43GJ80&Icjgh98eBa)DC~9YT6eJ8jaGA(ycz5+Twmt(p_|Sh`ajf3Ccdc9v(LgvRl1V5IO%l7}w8Rs;3(8h4Z5!X4aOv4PS3&sCLT${K7aXeNoh#zx`w3 z0kpfuH3t&iTDNLjjS!C%eqA#m-m*b2I*o@025e_$VDl&T)W68z-(^K_0d#a&1{--1 zV!LBc_rEE}>6$3t!JSojVMqQ3g+>mQxS?gQCwM(&DaXdA zU_}7368ROBhQr2LY(b>bpe*keGO6@a*9&w#hwOJMLpB%JQmWLvX@B@F=46=c#6{im zovk}Mk+*OkM4Pd0a5LVLvyv64PNuwJ>|4d?zqcLp1gg_4rS))oU&rCV%JgdH&(-VS z&rNq`vVCru=m%@|EG((X#}U-g#3ujI&L9zQ6V`(jH%r&(%t+*jK1- z0c%^?Nwx>ZvfAP;g~f&mw!ygP+x8{P>hc^)X8xrqLuCxsJgo-Omd0xCP}x0V3nQ!p zNo`z(D+t`C&$ramd_OR>WP1BBwN&|6_(N$g6vU``54Gbh9r}$a;|qA5>gJ7+uysX@ z-pKlE4!Mr1@m3hZ-lJp}k>O$uHRqf_%mHEfD4Lbi3q>EUF5OrkAiV0&4oYiXlSbi> zcVdrwi-jcsWbG%I6ewO99v*vIuw76mfyeu)YPFABWdD$e?o5E{<-KA|^WvPU&ne@| zIj3&E-uo3sP0v7TcyJ57SBcY%ahv*1v@x(sM)8T0ClEz3or?Q8G7HL2$ zAW+GrfEkv<*}bk5h;rKp8JbPwxa#W{F1O&`B3=9Id8_@sJx}8OB${?h(*kSJI+E@U zQ_BGHm8Ou;g8uNCpWY zP#c&(QKpI#25UIq?A!mq9>03dWi9{M>k(k?3{Xeso9RW9~nn= zZ9O($X)7!S8a>$bk$(-?&ws6)IaBsDmJqmoP7V{^7|g<9p!X8VCeloJ=DO2sjs zsg<*Sb|8O(OY5}XxrOgyXOMAh@t};@S`4E?zu$v;AKST}!KiDEpiX*oi3PRQwpM1k z_`@GzR2Z07(_bJV>5YT-qxy$#j%sUhemCbzCyZ)3(BXM7i00kyBj)j#ICu4s6+&-C zB^EMkQYLJwOO7O`q01WsJtq2S>_T}JvBZ3Z$VT6ky*R`iLmT%N!z#!cI$te~A@6QI z&d!R+$}SurgQYOKm73XmY~QGIN7>hAAJ$|&&VJtCZT{^%Z)SbBLS(2hX|z1d;O$O7 zMp(Gjg(CP@9k=%z?Cse##I@Qrm%`%pgTmr|x2n~-B*z!P@>)yh64=i>D-6;~YVpnQdrr0{)}Nkg)AqKvMj?zGW4hR&O5+7CS|4hV>;Bh7wt zL_)=8ckDHU>K*jlM`-)CBQ3Ujgp{h~;F*%$d#g4D5j&N;q??o0(jsmK{Dn?i64Xk=-0Dj*2wvy=enXA$wD>w2 zLegoy)Z-dCy~E>N3scXY4Xu?Nla>;zgwj*p>H=Qxq=N4rwHcZ=t7SS^W$x(J;Av)N zLEO-=9{Cq>aX8RhgtA#Hd?Ap*Zn$;Z=#+G?mGP}_PTZ&Tj3sW7QhDxngd(-8w|i*0 zgaKG|=NtJ*+hTC0O5x9o8?NCzl4IQ2z~a!7;zh^FA4Z~8TaL8N$%fpvX&OvV0}fWU z`^!eeSEa-eChp7u<%6agN{07wpb8n4avNqkeUjM(;N9;Zy)tE44V%J;JEwIxmgUF<#xW+lV1+6=IZf=uT`_Gj@7yn2AIJl z+`HAv)B+Rt(U$4KV)6GoHcaN9joip1{rml_Ir`Lt=Hb>XyggG6`i%}J{3*oWr zQ#2T5>(}XWShrhn$dss0n>Ij;*a_*i{LX#F+dMe3!XLnj{N|m*)jI|7Ki4t1*KI9) z^`qT2qM4{Uv=14KXjrxT;S}@TGe=N4QEF%k&wL3(!_H{tl6)6?n!tW@24Cyis#z<| z($>HuC;DWG3uBbJ-d-DZ!?E+Fxp0<{LrQ6A1Kl}<0H8gRY%9%nP0h)WIozE6tt6O9 zl4*&|;p7%w>S{pzAu+aMrWDAedKKM)I=d10?7{CPs`2#N!pd+go3tKF)=1wE>)bN7 zTptZV`Hiji;>K_Atkkr#h>pHKb#)8!$ncXwN^c9hC*@?>^8U*Z01K+_Ay+(`&+F%4 zhqJb^KvmL-FWyIx(DWwE+e`v>HXcKuJU zY)R&X^#y{k?hglJm-eZUOI1&q0X@>fOtmoWGOO`8zCU*5@m|>_w|(@=q4`?WKNNl- z{yLcLOXNVKc;{Sd$1TT4jT$PmLcWibj(A~vx8aXU;uH4H&ScD%X(^NQarc#rM_qm0+8~;odZqFG7mtz6M!r-`3Q_w9d*s zY4nr6SU~!-WC?>AWnx5thN{-~LSoVBO4Dh`N(r1LGsxK}C)I)W^z{?VEox5wSnx)4 zSlC*4AQ3d(NULpZagY~Y0K&?Lz^BI9Nfn9;D5vO#LT7QpIYDpiE=iNtr0a&R?zNP@ zDh-<7F~%WL37HvG!j8~63`+pmi12Q46kqH99BkT*5!P~r2v{6lH01V@NHe&zd8i0J z)-M=#tTxm5xWAU!r7o@7)gsR2BA2v#wiE0x=vQhfGvCb?+kWc1olxhVIuz%VR3A~h zCm!OSfLhoMr}<5YmNz_MxaNADn#HHdyNZpa#9VI%EuhDN1M;lQ_j7JFvTB(d?J`je zQ=7F2L6Do4FuBCsK3tuV)Umvflk^E?R=(62zkkN7wiNZ;ohyN0*^@j5 z^Lwe40vdIcX4~f!rMvAgyR}QkWW7L6K5sgc3|%*VeI7yoY`P#$&{bs#bQLEMo7XbP z8?bMm_T0X$itoBzgoIbFA58cKLBZRSom0sOn=k#Ne)6sQ1Ao0b*GJM!Vymq9galZq zfY>-Ms*+vcxq%A9A(6*bK*y$7*z0G6$MyQu`@-A;rS8%D`vQg))8^zNM2zr2_V4C` zk`Iy&r<3B>y!@bVQIhqExd|;y^grU_M#O{&U{zj0= z%ZEn)P$;gTOBbH;o8K6{RxZZ)RiE-!bGKZoO%)0nG*Jbi_WVLeOdW!Y?tBzkzKPbG zP)%974$4a#842wcS$J)}D}&@b>Mg@*V8plW)(1jU5c_kYgjKt_H6%_zAed4{<_ux;Qkp|yVv?C zgWcY=lOEwNXozbGwNOs|Xq}M~2WGd>YN;}ut?_JW3RPzwy}e4!5uXm4Hp$M+aA?dv zB%(85%`sN}-n|;klI{XwVK;i??56eAca3W*V$gsTXMvWRqTU_Nl^HQq(FL!64J&`) zq<(Cab8TJ)u{N{xNIhq2|JCliRH+qkKMHGzgBDu*Pe2F3sFtk9JGiSh9*(7=#e0S+xZ_Ua1E< z$N|-rq5IhFOW}*t-f2llzJkK}UQ?w%O?jnp2+joCA??vZ5C@6GriI_xTXzwSbuOXf zGWL}!Dl#rgFa8lipU@OBI_O*a2QF58h|Zk73rLnBiVA(9tGBN)6f@Hm(D-oDJ|wrP z`9v<5&}{k+r%W5m#yvA8Zqdv3Qyk)h}E zZoX|rhP=6h!=K~jW_q`HMxJwh`99;lJ9;LwNhvvLQSs3l0*nD-+AdmceRn}WLHmZlR z`+)t)nTtF{<*^}|(*~;qvIG)Eh`ZD*oLdEn8I?WFqnX`zrzAwX- z2>aGz$(A6SHpYg^IJb@f8<-!9&(W#ryXgz|%Q&pSQp|!vhCO1zl=tN@kzBi8?vYcn00MS z?iNEDK`_K%u~I}^e0Y9k=WV&Ij}F;KE__~y?56#LkAXkV+VaA$*mR8!zALP?c|kK3 zXM6GWaWiif{*J^XS)q=$(KKOsV_@#|kC*-e9qDp>+b!*w!1B(_r-9?{OepWD*aDI{ z$uxXqq0}V8c(Bb7b;<$%XcsCrR5f>NFOo_s?o){n+7C2h z9DT(jZ|2eJu@v=83yhGL9%IG}xoT$pe1<$Lo9(|dr?P%1FT1TY!RFpmtu?31nBcDO zS|D=e3czM4^Lvr)ep~{0?g$c#E8*xoy6Zh98gJvKFOY`d1bx=;6or6VPFhk>UrsF_ zzbuA-a&(r`jY*p?o^@M`Sm)_kCZX&vSNYJriHhe*g2)VnNOt*ZKzi(OO= zuf=GIFS-3q!>%8Bq?h03MNX|&I_gE)nm}$FmLDMd`d1I75Lm^w+_={yJ&DIr}ky{vx0`)ooyWWRihP_ zN!7CStlcUgbv#910Ce-4K}CkgT^VoI(}~VodDh-S7*hr*_A~0J+eLnM*Tfx1G%g|7 z1O+!NYQ=xU&&Rg6r?lUhXz>MJiDeAMFdOV5Ju95L)WRKI#bLTd?m5dhx?M~x_2ioS zdyiE9AV!CplNSV1d$n!d`tHLBvq@!=>cc)aYzNbIz35ZPb-GLedsO*gS@j`j>$rK5 z05_CF!;c_(-d6?KXFp}gXLP2BSt{(Pwm3Xwm9U#OXsr?xYV6m(D6zyMQNDOri?I1@t zP&xUn5s5Yh8PY(6$GjZyGeSIEEoL+<;E;Pr5A{$PaW?H+KgtRKP&MUCi*GjZGTRJV zI9N`-yAtTN*;2|+fcQxByJ)$)m))fn6k4&rO6%nBS5_L+VBxABLMd`)QH5q;Ffl=S zT9)`oEBj03kv?UR0VBbFo(iG{+aowj4_>=&!5?5nHG=|Nw#JaaBIgmKpQNxNFTguF z*-Sp#epT*_>XE`o*OIcq93pBYAR;@>NOtLC6EJKu_bR?9!{$PYcz$WgK10AO;Z{TB+BBbEok#f!4v~q6;$XnA|kz6fxNW$ zj6}h|aDO=CBFM1^X5Qu&r?Au+|0{lGP!^xu%?!7(<&sp3UHhoiZ@7kjrd7|fsA1SQabSIpNjHAs;Ti56YAl154l z`n#g@2n=v*P4eV}{%>LDs< z%zf3ys}9e3Z4tr6DRO1Ry_LZGT(N15WEkovvbHzsQ2$QE9c4vac05v{wzIQcAwQcA zn#<_BtW86|>36Y%IbF$l#vv?5=f+SpG1QHF`zZK#%QfIz@F$%y0Q`fI%ymXPz>&5q z<_6zjE^s5ZQK+iC5DbUCxqiPWa*v&Wtx>Z|D08){F%>`8Z{ruT3>U~Nm8sgPlx+ko<~1Pj za|#;G^*Ip6h8=T7j&O?)+#qjaV7Ge?r~w zaE$wMvo&iXcCo7)7WWYpLNr(X=xiqgr+3WJ_$F*@v;2){_BF?p`jw_N-y?V=qMX=h zOg1#Pd}sDxzT{p8MShp*MELD))X0}4>=$DBv}~89ABM`536alH?X=ygyAEZS?ISvuU)g4) z2xffC&J4wskor65<50w2z)YNNMFRi|9lr~m1#>o9f8GNv2~V8@;)j!ncWp$O-Ye)v z?GdzwT;F@8$E>Fa#2M@kFa1L?>Rb^g@mY|I;YV zn9DGZ5yXd4?p?Zpobi(4xbyi*%Nr9(tTrrVkNk)l2s_h znANTjX{2M@DDP@H-*)XV6SWec@5a8^Xlh}r>8 z`I$Fr5zo@wVrMiXFkm)=Z#+}=riGkXr1yp{5S>Ps8bLraguYIiju`snZ4)ocops_> zdx=*(N-)RW+q(jHiyp!}mf*PV!B5y;P8nEUF^??EU-z;Ksg0kiL=H^gJ*nw!`a`f4 zg=vT#;*~xLffzvQLivHB~to+z{Ng&R5OK3m7T|1g@t0 zU5Ld6s@d+EA*@6^}D?*II~fMwVQc4a$kPaViPvso?a)~1P|#g=*a^V>^i5mrcl z`+D}Rx(;ac0RU%Tt1(#*VRdu9IjueixzcozM=S{@41X5RZoRa~0&J?dA-A~|&RS5?$UhGfSXf#?&hAhP50f|A39%_2L6gWF=F{q`o+Z+j=oiRs10ww!ALjae&oKxLKZa_MWQo8_r9i6De~@U>S; z1KLxUTjQ zTYv3oP{J$Rb^pn`j#aq1bkT@Nl4R@sMUpV;Dxq`xhB#7W-cm-<5vw<+sne7gT<<{7 zBV1_w4U2g^4N6N_X}z4`XKlTsO=CI-uDqx=LHBv4k(NP^@Izb&`8RT^-;Y4eC2lLn z%8I`%J-a4F9G6Hb{J#~UVagGgVkf!I7mDjxMlS$SxrTz z8gAT84+Q>*j^pa}kO?1oxzS^P^^7vC_0GE5Q{AhH&8AMfy_RYH&zOjvmN|@L){g{s zVcQi`0B}9(5nRqDt$cSTgQi~n={#MuO(^A29EhV9N!x{1hN^OXU z-jDQVtPC=?gV*43F3W*PMSx(%$FsXHp~to`nhWOVwrD%Ni6DDvBT``+3(Sr0iYS$| z6~0gJh_wV~kskXekO40SyFNK&)8zNOtkNl45GUwVU*cVDuNKF z18jEu48b3}Rc?;xD|zba-CR&?l$*U~i@*S{l~3Idah>zc%!s4M4Nj!ImNoG;&Em`9 z)u??^M30@sJwvZsqCVxNt^CM{@A*iV;Vn=|IZ+cl&7Ui^sf#OmxZ4RxcSMuOCZxbv zYVrD(tbl1wx9V8n&A+qkJ5A>GeDkE>XC?QpSp+7m!uJQ^_{l^-_{l6B+sjKrc z>O;NtJZ(>^M(7%GqMtv`A#kP3vj@*n7Fh|cdDX&dUZl0j$yc01pq%&6UGw|o545M1 zxhH%|(eZ?jafQ?Fd*2$jgAy!UX{0d~eyx{YDeD9GZyq^xdNEdLbpr?3FbC_3=LsgY zxV9vBb{rOEpi`>bRV@GOzDSt_!|*_3(r{;KP4``@+>~_}5(+hLD6;I#6EvrP-r zyhfUvRT@azAzlDh)SQjQk_gOm7khFwB=wE8=`+tMmNN)wi>ez zRGOgn-fJ|OijltIgEw$Mf}2ySz94=!lNZc{=~xjD)>#IIf%`tf$>q(-nxWo5;~Sl9 z;jg(ta(Ie@^a~9u{s7D@$yA>w2S(G}2uP?k{V1OHy-xB#=gyMwD7;#=Csfxi=YnE? zDdo8D&hj&&Atm4MAz{igt==#49`(i954=Yi(=YUjItvU;Gb6(Cz|foD z_s1)nBKQq~Fu9j6ua+a@3$$bJl>o;CQ~kH4J+3wASee;Yhx=g+`{x_)X_Whp?wC)- zkEwRl&Lyz@Kcu~9P?K$-u8XKBAgCxHRgqqm-oy_O}i`>u3~J;Cao9$DUQWEd*F ziF$23j+-P00>G^o?PSqUR8DPMU1mUVU-Z%V(R|BH>%mbg7B7Q8$cLrMeAW;}?2XlL zmu=^XCNMVNZy8y>=qvAxO_hK=v>Vg!V9ch3Zm5J9FQ zqE_1E9wO2#IWhs($ zWDu(D+`;Fj3cpgW&OcOZd|@Y1YeIz^1QRH%cjJfhlk&E}-S^aMWuDFt3_!3pIHQGi zL?i3SY7aqCY;IIIi#@O9(J;WwJzYR-%#TPO9PGagZ_2D?E_}-gL&}+(g>$B`=Edb} zIO3{@D?fq2+-Cxk$~JuPd7M^ME&I=2We579OImg=kxiVe*c$2HX4OawPV9N zT(WL;aV)Euy0+F(GrN#==SC&Ic`jOF%C2MBv4ViHB3C)7nv4rw<>9Uu`MCdtyqcX+ z`*_Dhu0cxx8=>)5TAlxKvd(1THh>wK2N+~mIuefdsBnn5R?mWEg3A^={8+>zXmkyU2&dHj0G^r98j_IjgH zl*791`dyWD+7$xFOOs*YJ-H&lzYJJ$(Zz^0^9tG9f`wsTTbhMp@9ulsz?~(Qufj&g z4F+@Bhes+#YTj!uc!dAGv66+2Unco)z4LWYQ9#cbF+)3Kx*Z2=q(Y|of&lQC#|1K< z-*7(v7FQid!lYpzgnfvpgYLRE2phcA2McSx_= zW9^4FXp}v6*({amO4^*Ks0EryGojeE+kv^}5!Ke5BOw#2697?kHvvsp|4{aWo>fQd&F^x9xajJvAYe zc$erQ<+&3)ZC-xE55fFu1m!SUjda%SI6k=i77!K!bSo`khgyYWW$Pq%=7}N~Yn*7s z=iKK9p{MO(4cx7i-&5Hsrj>(`}ad8IAbh%#IT^@rROq;&N7m~ZTF4%)nnRiofeM(o8?kWsOZ4oSlXS>G4ur2{e5cJ7+>H3AmM&DPNtJ=_hy5{txY&o?oR z!E_r{v7g_2dsgHR%xBRp!>DW^KnQ3&-fGVZJ7fHU9@Rrw?)CR#yT0J-_Bs%}caK#R zI7OgF(Kp4Og`3UATASbcRm7)XiXk|k?PRyvi17G(+NQoJtOcw&KNjzin$7$Z;K;rY zODpLSvPngce2~l)m!%IWyD)78%s6rC9%o<4JKX)kX*2UZ_$5;hX#HIK%^of;S_lggMxhcACjYLJgO=WDz>SYhKUbe=+07OW*)s~62RHk0B1 zyqF2n$#XQ(o)Kxe@Oqi_v-kRSzL-Z^ZsO;gHb9KqjuiQ0GHq8=5t-sZu1(EI4q`F5 zWp<_dMLdtSnDeddpB8fM{0vNXJAI7~)i;Tvw@x()mh^36Vr;$2#;2Dci9plw+@_@3 zrg7mqJj$=imxSF7W|!Ay&v%eL$EupT`kL%BM`u^{&lg*HMlk}{9AxA#Rng`PbwlE7 zDVYR2L9_Xs?$I=8gUZ%j#z$i^jb=%xn$%g9J*$W2d9MacW(z3CHkpGShd1|FpEPs2 zkpvU-5B$Ie`ivvDUJEE`FlsNrNuKVj)VC?z0LMb(G+iLVDELM-pZz6TZ|zHD8FJcv zP;$V4SbLP$_Sc>8v|Q>uXVJz}tA816%evK;`AuPoT@7KkA3jz#Sm9?lF8uvRZS5(` z>Yr54Q;X{Nhq^6Yt?d?+TZaLH*3ounQx72BfJ;evLNP>_Dv^_xyuzR44-8N}84vQ# z5BV7{Uk%J28IzH9(*EU~p&Nw|W*>?_j+Sygl|S^OP`TZ0-n~mk&L*V7kJ!%9;q!cc z{$~eNw?zWM>XRjR`JR0EUze*I$tJwJEzOiaNpJ!?t+5VHv#r^L7uhf_0pm(Hi;T9w zk&2NOJHr}V{{ze96 z00Ta0$qSc0h3-F$&TJ!!T4J9!UeJP=K|;^#(Tk^im|h^J+C`SHFjaNiebxxkS!^&A+d&t9%B$M9W#uP6-j(bG4yI^t2pcmDZS0|QiG`8h;!v1C0 zv{%-aLJ6~JykZcmdW1tE&OO>FW_1ZyZ$0%~=Qvc?*xs2YR?gLW0PCgcR8%aILFycu z>%_o8!4VmcNN??-^Y>rBZNo+vVlVOHDhD<-nNPE{qj ztFSLV{phYoJL{1koxuVMm`Yl1qk#37%Klk1rY{L|Y-eg>-ol7@xdy((hPdM0W%y25 z<+JUzJ(;QzjXKKKReiq3vt6OM&hop~=QEo17dKZlq7wX&`PrrZL%Iw3l6EHhY64etwCWpqyU{9+mNXki*V9VJNTDjdfAhx2m3od`DECe+=FP*-F3J1ZDc4i zT{L$|tySeqF;N=rGoGoWb?VHGZK!M#8ofQxjOMNKcNm2E_L+WkG>D-?P6T{&d009W zZh-N7CP{~!1)01=yuXmteDx2L2O)eJx}4Vcz6IB`?4(EeHt`i$($*gI1unBYN=!HFuKO&0 zHOtH?BUeSib9VTw2jC4VS}4r&AB$)c6OpvTTsY@&nG(ubeaZhbSx2>V&%W@>+I`G0 zF#+f_8fo$p2ts!r*U1~`YwI>}PHTfh!AyBxH9-lF)7l776By-GYH2S`WMKMDLHheT zWrA@9p8&_J_@yNiL&;kQX#1=IJ$*4hPp3Nu%quu~T2f@NTx)qnPW*N!Jv|`Bj*d~G zj0_WAZ!>G0Z#+-Xwh)7Q9Jap}b5=nrW1XD^W$j7#r#MSfzO+tSNSyO{eXqIMoxg5V zUcjQKQ)yFyo>Z$mAnfc66RU6#6WvwSbo!MSPCt=E?f7xET^T#OE2m0oj8kxwI0d6y zi(+~*>2fhhp!lobNSJ?bV?BbUS|Ep0W-$j0@)Zty1q~IpQNjP}9bH?Q&Wv7imd)P+ z*cwlt_%BK8IgW1sA=<&2FKqPj&;H9`7Gbdz^S;C@C3nk_W7NJG>JuxDWyz}Ys3gRU z5X9q9W_kL7(@87y12@tfzDV7oD7;c1(dAA*T7H3`2?#l zTG%?Wx0lRO7IYyX4Z+(H|MZd!hU671?Hy_SJf_RHAZ6EH^!4e+h?<3nI55+x2%!|- z>acRGmHg!`B8j^qc z!X+=>XNDp$5$xh1oBU8S?YsX{MVZ&Qz6+gJ-r(T7HJ;TVT{PH;IPZ%Z(V>)nU6)N& z7#3Nn#)NVxypm5d5t$oo-2wex=gF0ou-qg$fO>Fown3k#Gzyh9Lq*1%yj6$4Zo{8& z!7GpG?h5F#=eYb-Qc7ygRBH9bxaV)={i+z%-pgxOZ381J?gAxlq}w^Z9I&I0A$quw zBeemZY5IQ$#+JT*1~F2Eic)xI=+ z0m#r*g{U3Jn;l2v2I1XM0k@2v#789BAR(kH@3 z-9`37gOtmF^9>X$ZCjd#ktnf*?6)5lowL+xyU!;`xMbNf5$UTEVhWV@OflzGy}o56 zD5ZpDmgq9ZUV8+I_%Raq(Ac~d05^InklII6UOp`7sHx%0nUfR`JdB%o<|6X^n?Z(A z4qwVx&>NnkTUu3a(^1K!nbC*dnJwG8t9xg!;Abg5S)V?M-gDdClhCfv6Keigrc9hf z%ks|r%W(GX1#39eg#Fbs_PC9e4^(#KsGev^wVwnGXlMYoLzkx}wKj3L@x=lHg2@|%dMhT$vVU6k-Zd3nqTL$CXTu?p!M!ml*-#`e)=oh*;_Rrj`zD~ugIGZlao z`v>fAM(l{ZKVYo2wjrCVc;^PnoTm3Vce!s`Pt~z{!gTKx!B@DHBfm z5d_7z#zn)d?=DB7dlm%Af>(ud2T(Y^ z9a{p{LKFl^A{F6B%pmVFkenA29_Hu1r8$2KNqE)F_$O$l3d?LvooQnLJ|?74o>jB1 zXlyXhD_h}~T-wyhC%O=wqNa7}8h>W8)juiYDvsh0gm%fKtd;jtc{sGQy=- z*#1-{j2!+vjcgROXyG*+SnXw3b&=rhb+9LFRo3`s+$Y&!cICUZRTCmQw)kS{;W zy~&r8hwUK{71{U)hs*Hpv?gF3g&ZKUHFUXtFM2jwB zbE7e_SJZBE({_ZfOxS?fFh0xeQUFYAVNnv0vjYOp+~%G(jcFZ9(j|AcmqQkC!k?(` z{K?DKD}#rY$FOiVpRKBx!*iq)&cDNqNRUhN&ycX`Qss$>3L+i=tGz1%dlTuce*K

G`eOUX0cTXqYFPV7&c+!|D#;> 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 B0+#>) literal 0 HcmV?d00001 diff --git a/packages/woocommerce-trusted-shops/assets/images/ts/ts_shop_review_sticker_de.jpg b/packages/woocommerce-trusted-shops/assets/images/ts/ts_shop_review_sticker_de.jpg new file mode 100755 index 0000000000000000000000000000000000000000..40af65da354682ce4feb67f4a4902eefe2956e96 GIT binary patch literal 71078 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 literal 0 HcmV?d00001 diff --git a/packages/woocommerce-trusted-shops/assets/images/ts/ts_shop_review_sticker_en.jpg b/packages/woocommerce-trusted-shops/assets/images/ts/ts_shop_review_sticker_en.jpg new file mode 100755 index 0000000000000000000000000000000000000000..0018483431fb13b53cc3d4d0948b2e6868e2e041 GIT binary patch literal 70150 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%0Do!fAzg zhQh~@Pp>7@$UV7aX4^1!O&2@y1Ue`=0{%pjFZR6hB5$JGH_lawHX|vxQ%zXztiATo zd4Q6Ix72N6dBf+`FVBM1mK1Q*@n-cpr4hO4T_ntW$R@}RKB1pKM_<`+{Bp`Y{j;r? z@AWhopEjQB`b)Fi@HP0S~2vLgz&J`T*tXyTRjXBFvhSIe@34^~paCP#0t z^P|eauYWZsUT+z`HMUjP-C6JXWp1$BMd*{MS^x}#55>Ah#{4AyAnsM$C_Rh%fQe^tLqKhVh=6SF4n1cLrWZP24Xn#R(D`k zlc$%~2G(JE3vj$C)+)gNIbf8645h5YAHcA(@*)Za;57ebR2xfa+xRkiujAOHB4ALr zcRNowlFDmk7v(C4uO8GZaAq}2ZN^CAmd z3mfpak^j6kV3Y6&N0c>X$b;G#pOHKDoY#(8?DCAPRGu^^{H)SCR>3VriY_oxq^YdKXp%yk0_QaLU>;f1 zw{;uG_cN|Ayiyp#0X|FLR%YH%L1o#bqiyLfq^Zy#I>!&2v}3LQTA0RDE0=QoJ>c9~ z97yWRcEhb_*7`$TsBhlU z?@qD|w00LK$jcn%L05*^`@gm=ZYSZ)e-mD-fuCCGC0148q$|vbnL$M@qU|KT8D@N| zw|>rm{#4x0)0VHp71pSY1z2kPodjeXo>6s(+mxVxgVfR{Y^xcdMc1+nFS6KD>etKe z>hlYEQoqRe3Y~bKXbyF+x1OkIi~0_%fjYAI8s`SPqCf)|Qo~?>p##LS!)PEM3 zUUGlkfQshJi*OR`spQC%c?%Yrmopw(F?bu6T^H)$oP5QpT<&lU`EfO>qWKOYt=b?V z0wdU)=}IR>U%%&DkIa-+Rp}~0{s`X_byC~f9*xVP6kwHMR;}o_+Vm*aF9udEv4 zR!^v;h$bfGBM+YZePtA0;$&wpS|7+vr`||5qB_2%HjhDWN`F)a z)D^IcCRjJ}e;Zru_!j<-f1BhTMGy!#ilkD)EZ8np^!IGKNllKZ1H(N#GIuiwlX

r+6UCu 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 literal 0 HcmV?d00001 diff --git a/packages/woocommerce-trusted-shops/assets/images/ts/ts_shop_review_sticker_fr.jpg b/packages/woocommerce-trusted-shops/assets/images/ts/ts_shop_review_sticker_fr.jpg new file mode 100755 index 0000000000000000000000000000000000000000..5ccb33e6eb8dd07207f0bf590d2033d29b57fdd2 GIT binary patch literal 72007 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

{g(+qv248RJXhzeUX=qSEoRc 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

^(bby>2 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 z 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 E4?d?5kpKVy literal 0 HcmV?d00001 diff --git a/packages/woocommerce-trusted-shops/assets/images/ts/ts_trustbadge_trustmark_reviews_en.png b/packages/woocommerce-trusted-shops/assets/images/ts/ts_trustbadge_trustmark_reviews_en.png new file mode 100755 index 0000000000000000000000000000000000000000..ffec5272d1170a4e32e08d11b8e8ceb6d540ba8c GIT binary patch literal 44454 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 SE|mcRe`-ovina2VA^!)tg+0sw literal 0 HcmV?d00001 diff --git a/packages/woocommerce-trusted-shops/assets/images/ts/ts_trustbadge_trustmark_reviews_fr.png b/packages/woocommerce-trusted-shops/assets/images/ts/ts_trustbadge_trustmark_reviews_fr.png new file mode 100755 index 0000000000000000000000000000000000000000..23ef1a4da567d3374cf37f851e60a9fed94bb7c8 GIT binary patch literal 44138 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

    $ycWj~WId)P`B^Ex4t%`p2?o_Tb_fag!%bBCJ4 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

    ToA(P3VP7&BmP#z(Rtq&IH6|jo1B9B^A(EWEM~o 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 z

  1. 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 eM8(eh6od6F^x^6xs8|;S+@7oHs#ZO1y=BD-l literal 0 HcmV?d00001 diff --git a/packages/woocommerce-trusted-shops/assets/images/ts/ts_woo_de.jpg b/packages/woocommerce-trusted-shops/assets/images/ts/ts_woo_de.jpg new file mode 100755 index 0000000000000000000000000000000000000000..1b06c4cccd9167eb0ce43527d0f112b32ff217a6 GIT binary patch literal 77174 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%0A*5ye`n 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 literal 0 HcmV?d00001 diff --git a/packages/woocommerce-trusted-shops/assets/images/ts/ts_woo_en.jpg b/packages/woocommerce-trusted-shops/assets/images/ts/ts_woo_en.jpg new file mode 100755 index 0000000000000000000000000000000000000000..d9cb674c0df01a03f562028370e49cca9ca16abd GIT binary patch literal 75591 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' ); + + $( 'html, body' ).animate( { + scrollTop: ( self.getSettingsWrapper().offset().top - 100 ) + }, 1000 ); + }, + + validate: function( $elem ) { + var self = trusted_shops.admin, + isValid = true, + id = $elem.attr( 'id' ), + isCode = id.substr( id.length - 5 ) === '_code', + value = $elem.val(); + + if ( $elem.data( 'validate' ) ) { + var type = $elem.data( 'validate' ); + + if ( 'integer' === type ) { + value = parseInt( value ); + + if ( isNaN( value ) ) { + isValid = false; + } + } + } else if( self.isExpertMode() && isCode ) { + if ( '' === value ) { + isValid = false; + } + } + + return isValid; + }, + + onSaveForm: function() { + var self = trusted_shops.admin; + var doSubmit = true; + + $( 'textarea, input, select' ).removeClass( 'wc-ts-has-error' ); + + $( 'textarea:visible, input:visible, select:visible' ).each( function() { + + var id = $( this ).attr( 'id' ), + isCode = id.substr( id.length - 5 ) === '_code', + $td = $( this ).parents( 'tr' ).find( 'td' ); + + $td.find( '.wc-ts-error' ).remove(); + + if ( ! self.validate( $( this ) ) ) { + $( this ).addClass( 'wc-ts-has-error' ); + + if ( isCode ) { + var message = self.params.i18n_error_mandatory; + } else { + var message = $( this ).data( 'validate-msg' ); + } + + $td.append( '' + message + '' ); + + doSubmit = false; + } + }); + + if ( ! doSubmit ) { + $( 'html, body' ).animate( { + scrollTop: ( self.getSettingsWrapper().find( '.wc-ts-has-error:first' ).offset().top - 100 ) + }, 1000 ); + } + + return doSubmit; + }, + + isExpertMode: function() { + var self = trusted_shops.admin; + return $( '#woocommerce_' + this.optionPrefix + 'trusted_shops_integration_mode' ).val() === 'expert'; + }, + + onClickExport: function() { + var self = trusted_shops.admin; + var href_org = $( this ).data( 'href-org' ); + + $( this ).attr( 'href', href_org + '&interval=' + $( '#woocommerce_' + self.optionPrefix + 'trusted_shops_review_collector' ).val() + '&days=' + $( '#woocommerce_' + self.params.option_prefix + 'trusted_shops_review_collector_days_to_send' ).val() ); + } + }; + + $( document ).ready( function() { + trusted_shops.admin.init(); + }); + +})( jQuery, wp, window.trusted_shops ); \ No newline at end of file diff --git a/packages/woocommerce-trusted-shops/assets/js/admin.min.js b/packages/woocommerce-trusted-shops/assets/js/admin.min.js new file mode 100644 index 000000000..6d3e2bf56 --- /dev/null +++ b/packages/woocommerce-trusted-shops/assets/js/admin.min.js @@ -0,0 +1 @@ +window.trusted_shops=window.trusted_shops||{},function(s,a){a.admin={params:{},optionPrefix:"",init:function(){this.params=trusted_shops_params,this.optionPrefix=this.params.option_prefix;var e=this;s(document).on("click","a.woocommerce-ts-input-toggle-trigger",this.onInputToogleClick),s(document).on("change","#woocommerce_"+this.optionPrefix+"trusted_shops_integration_mode",this.onChangeIntegrationMode),s(document).on("change",":input[id$=_enable]",this.onChangeEnable),s(document).on("change","#woocommerce_"+this.optionPrefix+"trusted_shops_reviews_enable",this.onChangeEnableReviews),s(document).find("#woocommerce_"+this.optionPrefix+"trusted_shops_integration_mode").trigger("change"),s(document).find(":input[id$=_enable]").trigger("change"),s(document).on("click","#wc-gzd-trusted-shops-export",this.onClickExport),s(document).on("click","table.form-table tr",this.onSidebarChange),s(":data(sidebar)").each(function(){s(this).parents("tr").on("click",e.onSidebarChange)}),s(document).on("click",'h2, div[id$="options-description"]',this.onSidebarTitelChange),s(document).on("submit","#mainform",this.onSaveForm)},onInputToogleClick:function(){var e=s(this).find("span.woocommerce-ts-input-toggle"),t=e.parents("tr").find("input[type=checkbox]"),o=e.hasClass("woocommerce-input-toggle--enabled");return e.removeClass("woocommerce-input-toggle--enabled"),e.removeClass("woocommerce-input-toggle--disabled"),o?(t.prop("checked",!1),e.addClass("woocommerce-input-toggle--disabled")):(t.prop("checked",!0),e.addClass("woocommerce-input-toggle--enabled")),t.trigger("change"),!1},onChangeEnableReviews:function(){var e=a.admin;s(this).is(":checked")?(s(document).find("#woocommerce_"+e.optionPrefix+"trusted_shops_product_sticker_enable").parents("tr").show(),s(document).find("#woocommerce_"+e.optionPrefix+"trusted_shops_product_widget_enable").parents("tr").show(),s(document).find("#woocommerce_"+e.optionPrefix+"trusted_shops_brand_attribute").parents("tr").show()):(s(document).find("#woocommerce_"+e.optionPrefix+"trusted_shops_product_sticker_enable").prop("checked",!1),s(document).find("#woocommerce_"+e.optionPrefix+"trusted_shops_product_widget_enable").prop("checked",!1),s(document).find("#woocommerce_"+e.optionPrefix+"trusted_shops_product_sticker_enable").parents("tr").hide(),s(document).find("#woocommerce_"+e.optionPrefix+"trusted_shops_product_widget_enable").parents("tr").hide(),s(document).find("#woocommerce_"+e.optionPrefix+"trusted_shops_brand_attribute").parents("tr").hide()),s(document).find("#woocommerce_"+e.optionPrefix+"trusted_shops_product_sticker_enable").trigger("change"),s(document).find("#woocommerce_"+e.optionPrefix+"trusted_shops_product_widget_enable").trigger("change")},onChangeIntegrationMode:function(){a.admin;s(document).find(":input[id$=_enable]").trigger("change")},onChangeEnable:function(){(self=a.admin).showHideGroupElements(s(this))},showHideGroupElements:function(e){var t=e.attr("id"),o=a.admin,t=t.replace("woocommerce_"+o.optionPrefix+"trusted_shops_",""),i=t.substr(0,t.length-7),t=s(":input[id^=woocommerce_"+o.optionPrefix+"trusted_shops_"+i+"_], th[id^=woocommerce_"+o.optionPrefix+"trusted_shops_"+i+"_]"),r=!1,n=["woocommerce_"+o.optionPrefix+"trusted_shops_rich_snippets_category","woocommerce_"+o.optionPrefix+"trusted_shops_rich_snippets_product","woocommerce_"+o.optionPrefix+"trusted_shops_rich_snippets_home","woocommerce_"+o.optionPrefix+"trusted_shops_product_sticker_tab_text"];e.is(":checked")&&(r=!0),t.each(function(){var e=s(this).attr("id"),t=r;"woocommerce_"+o.optionPrefix+"trusted_shops_"+i+"_enable"!==e&&("woocommerce_"+o.optionPrefix+"trusted_shops_"+i+"_code"===e||"woocommerce_"+o.optionPrefix+"trusted_shops_"+i+"_selector"===e?!o.isExpertMode()&&t&&(t=!1):o.isExpertMode()&&0

    '+t.join("
    ")+"

    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 literal 0 HcmV?d00001 diff --git a/packages/woocommerce-trusted-shops/assets/js/admin.js b/packages/woocommerce-trusted-shops/assets/js/admin.js new file mode 100644 index 000000000..53e4f9200 --- /dev/null +++ b/packages/woocommerce-trusted-shops/assets/js/admin.js @@ -0,0 +1,278 @@ +/*global woocommerce_admin_meta_boxes, woocommerce_admin, accounting, woocommerce_admin_meta_boxes_order */ +window.trusted_shops = window.trusted_shops || {}; + +( function( $, wp, trusted_shops ) { + + /** + * Order Data Panel + */ + trusted_shops.admin = { + + params: {}, + optionPrefix: '', + + init: function() { + this.params = trusted_shops_params; + this.optionPrefix = this.params.option_prefix; + var self = this; + + $( document ).on( 'click', 'a.woocommerce-ts-input-toggle-trigger', this.onInputToogleClick ); + + // Show hide elements + $( document ).on( 'change', '#woocommerce_' + this.optionPrefix + 'trusted_shops_integration_mode', this.onChangeIntegrationMode ); + $( document ).on( 'change', ':input[id$=_enable]', this.onChangeEnable ); + $( document ).on( 'change', '#woocommerce_' + this.optionPrefix + 'trusted_shops_reviews_enable', this.onChangeEnableReviews ); + + // Initial triggers + $( document ).find( '#woocommerce_' + this.optionPrefix + 'trusted_shops_integration_mode' ).trigger( 'change' ); + $( document ).find( ':input[id$=_enable]' ).trigger( 'change' ); + + // Exporter + $( document ).on( 'click', '#wc-gzd-trusted-shops-export', this.onClickExport ); + + // Sidebar Switch + $( document ).on( 'click', 'table.form-table tr', this.onSidebarChange ); + + $( ":data(sidebar)" ).each( function() { + $( this ).parents( 'tr' ).on( 'click', self.onSidebarChange ); + }); + + $( document ).on( 'click', 'h2, div[id$="options-description"]', this.onSidebarTitelChange ); + + // Form validation + $( document ).on( 'submit', '#mainform', this.onSaveForm ); + }, + + onInputToogleClick: function() { + var $toggle = $( this ).find( 'span.woocommerce-ts-input-toggle' ), + $row = $toggle.parents( 'tr' ), + $checkbox = $row.find( 'input[type=checkbox]' ), + $enabled = $toggle.hasClass( 'woocommerce-input-toggle--enabled' ); + + $toggle.removeClass( 'woocommerce-input-toggle--enabled' ); + $toggle.removeClass( 'woocommerce-input-toggle--disabled' ); + + if ( $enabled ) { + $checkbox.prop( 'checked', false ); + $toggle.addClass( 'woocommerce-input-toggle--disabled' ); + } else { + $checkbox.prop( 'checked', true ); + $toggle.addClass( 'woocommerce-input-toggle--enabled' ); + } + + $checkbox.trigger( 'change' ); + + return false; + }, + + onChangeEnableReviews: function() { + var self = trusted_shops.admin; + + if ( $( this ).is( ':checked' ) ) { + $( document ).find( '#woocommerce_' + self.optionPrefix + 'trusted_shops_product_sticker_enable' ).parents( 'tr' ).show(); + $( document ).find( '#woocommerce_' + self.optionPrefix + 'trusted_shops_product_widget_enable' ).parents( 'tr' ).show(); + $( document ).find( '#woocommerce_' + self.optionPrefix + 'trusted_shops_brand_attribute' ).parents( 'tr' ).show(); + } else { + $( document ).find( '#woocommerce_' + self.optionPrefix + 'trusted_shops_product_sticker_enable' ).prop( 'checked', false ); + $( document ).find( '#woocommerce_' + self.optionPrefix + 'trusted_shops_product_widget_enable' ).prop( 'checked', false ); + + $( document ).find( '#woocommerce_' + self.optionPrefix + 'trusted_shops_product_sticker_enable' ).parents( 'tr' ).hide(); + $( document ).find( '#woocommerce_' + self.optionPrefix + 'trusted_shops_product_widget_enable' ).parents( 'tr' ).hide(); + $( document ).find( '#woocommerce_' + self.optionPrefix + 'trusted_shops_brand_attribute' ).parents( 'tr' ).hide(); + } + + $( document ).find( '#woocommerce_' + self.optionPrefix + 'trusted_shops_product_sticker_enable' ).trigger( 'change' ); + $( document ).find( '#woocommerce_' + self.optionPrefix + 'trusted_shops_product_widget_enable' ).trigger( 'change' ); + }, + + onChangeIntegrationMode: function() { + var self = trusted_shops.admin; + + $( document ).find( ':input[id$=_enable]' ).trigger( 'change' ); + }, + + onChangeEnable: function() { + self = trusted_shops.admin; + self.showHideGroupElements( $( this ) ); + }, + + showHideGroupElements: function( $parent ) { + var id = $parent.attr( 'id' ), + self = trusted_shops.admin, + postfix = id.replace( 'woocommerce_' + self.optionPrefix + 'trusted_shops_', '' ), + group = postfix.substr( 0, postfix.length - 7 ), + // Support inputs and HTML fields + $elements = $( ':input[id^=woocommerce_' + self.optionPrefix + 'trusted_shops_' + group + '_], th[id^=woocommerce_' + self.optionPrefix + 'trusted_shops_' + group + '_]' ), + show = false; + + var exclude_hide_experts = [ + 'woocommerce_' + self.optionPrefix + 'trusted_shops_rich_snippets_category', + 'woocommerce_' + self.optionPrefix + 'trusted_shops_rich_snippets_product', + 'woocommerce_' + self.optionPrefix + 'trusted_shops_rich_snippets_home', + 'woocommerce_' + self.optionPrefix + 'trusted_shops_product_sticker_tab_text' + ]; + + if ( $parent.is( ':checked' ) ) { + show = true; + } + + $elements.each( function() { + var elementId = $( this ).attr( 'id' ); + var showElement = show; + + if ( 'woocommerce_' + self.optionPrefix + 'trusted_shops_' + group + '_enable' === elementId ) { + return; + } + + // Code blocks + if ( 'woocommerce_' + self.optionPrefix + 'trusted_shops_' + group + '_code' === elementId || 'woocommerce_' + self.optionPrefix + 'trusted_shops_' + group + '_selector' === elementId ) { + if ( ! self.isExpertMode() && showElement ) { + showElement = false; + } + } else if( self.isExpertMode() ) { + // Check if parent has code block + var $parent = $( this ).parents( 'table.form-table' ); + + // Check if element is excluded from being hidden + if ( $parent.find( ':input[id$=_code]' ).length > 0 ) { + if ( $.inArray( elementId, exclude_hide_experts ) == -1 ) { + showElement = false; + } + } + } + + if ( showElement ) { + $( this ).parents( 'tr' ).show(); + } else { + $( this ).parents( 'tr' ).hide(); + } + }); + }, + + onSidebarTitelChange: function() { + var $next = $( this ).nextAll( 'table.form-table:first' ); + $next.find( 'tr:first' ).trigger( 'click' ); + }, + + onSidebarChange: function() { + var $sidebar_elem = $( this ).find( '[data-sidebar]' ), + $table = $( this ).parents( '.form-table' ), + $current_sidebar = $( '.wc-ts-sidebar-active' ), + $sidebar = $current_sidebar; + + if ( $sidebar_elem.length <= 0 ) { + if ( $table.find( '[data-sidebar]' ).length > 0 ) { + $sidebar_elem = $table.find( '[data-sidebar]:first' ); + } + } + + if ( $sidebar_elem.length <= 0 ) { + $sidebar = $( '#wc-ts-sidebar-default' ); + } else { + $sidebar = $( '#' + $sidebar_elem.data( 'sidebar' ) ); + } + + $current_sidebar.removeClass( 'wc-ts-sidebar-active' ); + $sidebar.addClass( 'wc-ts-sidebar-active' ); + }, + + getSettingsWrapper: function() { + var self = trusted_shops.admin; + var prefix = self.optionPrefix.replace( '_', '-' ); + + return $( '.wc-' + prefix + 'admin-settings' ); + }, + + addNotice: function( type, texts ) { + var self = trusted_shops.admin; + + self.getSettingsWrapper().find( '#message' ).remove(); + self.getSettingsWrapper().prepend( '

&7sD_7BGoz%<&HFu_}t!Idy}2~r&9Ef0+O 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 L{M#Q%9vA*UoUOWI literal 0 HcmV?d00001 diff --git a/packages/woocommerce-trusted-shops/assets/images/ts/ts_trustbadge_trustmark-only_de.png b/packages/woocommerce-trusted-shops/assets/images/ts/ts_trustbadge_trustmark-only_de.png new file mode 100644 index 0000000000000000000000000000000000000000..da01f86c41876346b11baf3478cae33f79640d8c GIT binary patch literal 21913 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

"),s("html, body").animate({scrollTop:o.getSettingsWrapper().offset().top-100},1e3)},validate:function(e){var t=a.admin,o=!0,i=e.attr("id"),i="_code"===i.substr(i.length-5),r=e.val();return e.data("validate")?"integer"===e.data("validate")&&(r=parseInt(r),isNaN(r)&&(o=!1)):t.isExpertMode()&&i&&""===r&&(o=!1),o},onSaveForm:function(){var o=a.admin,i=!0;return s("textarea, input, select").removeClass("wc-ts-has-error"),s("textarea:visible, input:visible, select:visible").each(function(){var e=s(this).attr("id"),e="_code"===e.substr(e.length-5),t=s(this).parents("tr").find("td");t.find(".wc-ts-error").remove(),o.validate(s(this))||(s(this).addClass("wc-ts-has-error"),e=e?o.params.i18n_error_mandatory:s(this).data("validate-msg"),t.append(''+e+""),i=!1)}),i||s("html, body").animate({scrollTop:o.getSettingsWrapper().find(".wc-ts-has-error:first").offset().top-100},1e3),i},isExpertMode:function(){a.admin;return"expert"===s("#woocommerce_"+this.optionPrefix+"trusted_shops_integration_mode").val()},onClickExport:function(){var e=a.admin,t=s(this).data("href-org");s(this).attr("href",t+"&interval="+s("#woocommerce_"+e.optionPrefix+"trusted_shops_review_collector").val()+"&days="+s("#woocommerce_"+e.params.option_prefix+"trusted_shops_review_collector_days_to_send").val())}},s(document).ready(function(){a.admin.init()})}(jQuery,(wp,window.trusted_shops)); \ No newline at end of file diff --git a/packages/woocommerce-trusted-shops/i18n/languages/woocommerce-trusted-shops-de_DE.mo b/packages/woocommerce-trusted-shops/i18n/languages/woocommerce-trusted-shops-de_DE.mo new file mode 100644 index 0000000000000000000000000000000000000000..06afcb3b9f9a4fe49864ecd39fb10105dbd68847 GIT binary patch literal 25582 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 as)4?$25$ChRh-&~Jaj8%BV&&m&Ho3fmg`vn literal 0 HcmV?d00001 diff --git a/packages/woocommerce-trusted-shops/i18n/languages/woocommerce-trusted-shops-de_DE.po b/packages/woocommerce-trusted-shops/i18n/languages/woocommerce-trusted-shops-de_DE.po new file mode 100644 index 000000000..56fe16296 --- /dev/null +++ b/packages/woocommerce-trusted-shops/i18n/languages/woocommerce-trusted-shops-de_DE.po @@ -0,0 +1,1166 @@ +msgid "" +msgstr "" +"Project-Id-Version: WooCommerce Trusted Shops\n" +"POT-Creation-Date: 2019-10-30 17:53+0100\n" +"PO-Revision-Date: 2019-10-30 19:17+0100\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: de_DE\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 2.2.4\n" +"X-Poedit-Basepath: ../..\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Poedit-KeywordsList: __;_e;__ngettext:1,2;_n:1,2;__ngettext_noop:1,2;" +"_n_noop:1,2;_c,_nc:4c,1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;_nx_noop:4c,1,2;" +"esc_attr_e;esc_html_e;esc_html__\n" +"X-Poedit-SearchPath-0: .\n" +"X-Poedit-SearchPathExcluded-0: node_modules\n" +"X-Poedit-SearchPathExcluded-1: vendor\n" + +#: includes/admin/settings/class-wc-ts-gzd-settings-tab.php:48 +msgctxt "trusted-shops" +msgid "Setup your Trusted Shops Integration." +msgstr "Setze deine Trusted Shops Integration auf." + +#: includes/admin/settings/class-wc-ts-gzd-settings-tab.php:52 +#: includes/class-wc-ts-settings-handler.php:23 +msgctxt "trusted-shops" +msgid "Trusted Shops" +msgstr "Trusted Shops" + +#: includes/admin/views/html-notice-dependencies.php:16 +msgctxt "trusted-shops" +msgid "Dependencies Missing or Outdated" +msgstr "Wichtige Plugins fehlen oder sind veraltet" + +#: includes/admin/views/html-notice-dependencies.php:24 +msgctxt "trusted-shops" +msgid "" +"To use WooCommerce Trusted Shops you may at first install the following " +"plugins:" +msgstr "" +"Um WooCommerce Trusted Shops zuverlässig nutzen zu können, musst du erst " +"folgende Plugins installieren:" + +#: includes/admin/views/html-notice-dependencies.php:28 +#, php-format +msgctxt "trusted-shops" +msgid "Install %s" +msgstr "Install %s" + +#: includes/admin/views/html-notice-dependencies.php:36 +msgctxt "trusted-shops" +msgid "" +"To use WooCommerce Trusted Shops you may at first update the following " +"plugins to a newer version:" +msgstr "" +"Um WooCommerce Trusted Shops zuverlässig nutzen zu können, update bitte " +"folgende Plugins:" + +#: includes/admin/views/html-notice-dependencies.php:40 +#, php-format +msgctxt "trusted-shops" +msgid "%s required in at least version %s" +msgstr "%s wird mindestens in Version %s benötigt" + +#: includes/admin/views/html-notice-dependencies.php:49 +msgctxt "trusted-shops" +msgid "Check for Updates" +msgstr "nach Updates suchen" + +#: includes/admin/views/html-notice-dependencies.php:50 +msgctxt "trusted-shops" +msgid "or" +msgstr "oder" + +#: includes/admin/views/html-notice-dependencies.php:51 +msgctxt "trusted-shops" +msgid "Install an older version" +msgstr "Installiere eine ältere Version" + +#: includes/admin/views/html-notice-update.php:14 +msgctxt "trusted-shops" +msgid "" +"WooCommerce Trusted Shops Data Update Required – We " +"just need to update your installation to the latest version" +msgstr "" +"WooCommerce Trusted Shops Datenaktualisierung erforderlich " +"– Wir müssen deine Installation auf die neueste Version updaten" + +#: includes/admin/views/html-notice-update.php:15 +msgctxt "trusted-shops" +msgid "Run the updater" +msgstr "Update starten" + +#: includes/admin/views/html-notice-update.php:19 +msgctxt "trusted-shops" +msgid "" +"It is strongly recommended that you backup your database before proceeding. " +"Are you sure you wish to run the updater now?" +msgstr "" +"Du solltest vor einem Update immer ein Backup deiner Datenbank anlegen. Bist " +"du sicher das Update jetzt zu installieren?" + +#: includes/admin/views/html-wpml-notice.php:11 +msgctxt "trusted-shops" +msgid "WPML Support" +msgstr "WPML Unterstützung" + +#: includes/admin/views/html-wpml-notice.php:14 +msgctxt "trusted-shops" +msgid "" +"These settings serve as default settings for all your languages. To adjust " +"the settings for a certain language, please switch your admin language " +"through the WPML language switcher and adjust the corresponding settings." +msgstr "" +"Diese Einstellungen werden als Standard für alle deine Sprachen verwendet. " +"Um die Einstellungen für eine spezielle Sprache zu ändern, wechsle bitte zur " +"entsprechenden Sprache über den WPML Sprachumschalter." + +#: includes/admin/views/html-wpml-notice.php:16 +#, php-format +msgctxt "trusted-shops" +msgid "" +"These settings apply for your %s shop. To adjust settings for another " +"language, please switch your admin language through the WPML language " +"switcher." +msgstr "" +"Diese Einstellungen werden für deinen %s Shop verwendet. Um die " +"Einstellungen für eine andere Sprache anzupassen, wechsle bitte die Sprache " +"über den WPML Sprachumschalter." + +#: includes/class-wc-trusted-shops-admin.php:84 +#: includes/class-wc-trusted-shops-admin.php:121 +msgctxt "trusted-shops" +msgid "GTIN" +msgstr "GTIN" + +#: includes/class-wc-trusted-shops-admin.php:84 +#: includes/class-wc-trusted-shops-admin.php:121 +msgctxt "trusted-shops" +msgid "" +"ID that allows your products to be identified worldwide. If you want to " +"display your Trusted Shops Product Reviews in Google Shopping and paid " +"Google adverts, Google needs the GTIN." +msgstr "" +"Identifikationsnummer, mit der Produkte weltweit eindeutig identifiziert " +"werden können. Wenn du deine Trusted Shops Produktbewertungen in Google " +"Shopping und bezahlten Google Produktanzeigen ausspielen möchtest, benötigt " +"Google die GTIN." + +#: includes/class-wc-trusted-shops-admin.php:88 +#: includes/class-wc-trusted-shops-admin.php:122 +msgctxt "trusted-shops" +msgid "MPN" +msgstr "MPN" + +#: includes/class-wc-trusted-shops-admin.php:88 +#: includes/class-wc-trusted-shops-admin.php:122 +msgctxt "trusted-shops" +msgid "" +"If you don't have a GTIN for your products, you can pass the brand name and " +"the MPN on to Google to use the Trusted Shops Google Integration." +msgstr "" +"Wenn deine Produkte keine GTIN haben, kannst du den Markennamen zusammen mit " +"der MPN übergeben, um die Trusted Shops Google Integration zu nutzen." + +#: includes/class-wc-trusted-shops-admin.php:142 +msgctxt "trusted-shops" +msgid "Brand" +msgstr "Marke" + +#: includes/class-wc-trusted-shops-admin.php:176 +msgctxt "trusted-shops" +msgid "This field is mandatory" +msgstr "Dieses Feld ist ein Pflichtfeld" + +#: includes/class-wc-trusted-shops-admin.php:183 +msgctxt "trusted-shops" +msgid "Trusted Shops Options" +msgstr "Trusted Shops" + +#: includes/class-wc-trusted-shops-admin.php:190 +msgctxt "trusted-shops" +msgid "Arial" +msgstr "Arial" + +#: includes/class-wc-trusted-shops-admin.php:191 +msgctxt "trusted-shops" +msgid "Geneva" +msgstr "Geneva" + +#: includes/class-wc-trusted-shops-admin.php:192 +msgctxt "trusted-shops" +msgid "Georgia" +msgstr "Georgia" + +#: includes/class-wc-trusted-shops-admin.php:193 +msgctxt "trusted-shops" +msgid "Helvetica" +msgstr "Helvetica" + +#: includes/class-wc-trusted-shops-admin.php:194 +msgctxt "trusted-shops" +msgid "Sans-serif" +msgstr "Sans-serif" + +#: includes/class-wc-trusted-shops-admin.php:195 +msgctxt "trusted-shops" +msgid "Serif" +msgstr "Serif" + +#: includes/class-wc-trusted-shops-admin.php:196 +msgctxt "trusted-shops" +msgid "Trebuchet MS" +msgstr "Trebuchet MS" + +#: includes/class-wc-trusted-shops-admin.php:197 +msgctxt "trusted-shops" +msgid "Verdana" +msgstr "Verdana" + +#: includes/class-wc-trusted-shops-admin.php:220 +msgctxt "trusted-shops" +msgid "Trusted Shops Integration" +msgstr "Trusted Shops Integration" + +#: includes/class-wc-trusted-shops-admin.php:221 +#, php-format +msgctxt "trusted-shops" +msgid "Do you need help with integrating your Trustbadge? %s" +msgstr "Brauchst du Hilfe bei der Einbindung deines Trustbadges? %s" + +#: includes/class-wc-trusted-shops-admin.php:221 +msgctxt "trusted-shops" +msgid "To the step-by-step instructions" +msgstr "Zur Schritt-für-Schritt Anleitung" + +#: includes/class-wc-trusted-shops-admin.php:227 +msgctxt "trusted-shops" +msgid "Trusted Shops ID" +msgstr "Trusted Shops ID" + +#: includes/class-wc-trusted-shops-admin.php:228 +msgctxt "trusted-shops" +msgid "" +"The Trusted Shops ID is a unique identifier for your shop. You can find your " +"Trusted Shops ID in your My Trusted Shops account." +msgstr "" +"Die Trusted Shops ID identifiziert deinen Shop eindeutig bei Trusted Shops. " +"Du findest deine Trusted Shops ID in deinem My Trusted Shops Account." + +#: includes/class-wc-trusted-shops-admin.php:237 +msgctxt "trusted-shops" +msgid "Edit Mode" +msgstr "Bearbeitungsmodus" + +#: includes/class-wc-trusted-shops-admin.php:239 +#: includes/class-wc-trusted-shops-admin.php:300 +#: includes/class-wc-trusted-shops-admin.php:423 +msgctxt "trusted-shops" +msgid "" +"The advanced configuration is for users with programming skills. Here you " +"can create even more individual settings." +msgstr "" +"Der Expertenmodus ist für fortgeschrittene Nutzer mit Programmierkenntnissen " +"gedacht. Hier kannst du noch mehr individuelle Einstellungen vornehmen." + +#: includes/class-wc-trusted-shops-admin.php:243 +msgctxt "trusted-shops" +msgid "Standard configuration" +msgstr "Standardmodus" + +#: includes/class-wc-trusted-shops-admin.php:244 +msgctxt "trusted-shops" +msgid "Advanced configuration" +msgstr "Expertenmodus" + +#: includes/class-wc-trusted-shops-admin.php:252 +msgctxt "trusted-shops" +msgid "Configure your Trustbadge" +msgstr "Konfiguriere dein Trustbadge" + +#: includes/class-wc-trusted-shops-admin.php:258 +msgctxt "trusted-shops" +msgid "Display Trustbadge" +msgstr "Trustbadge anzeigen" + +#: includes/class-wc-trusted-shops-admin.php:260 +msgctxt "trusted-shops" +msgid "Display the Trustbadge on all the pages of your shop." +msgstr "Zeige das Trustbadge auf allen Seiten deines Shops an." + +#: includes/class-wc-trusted-shops-admin.php:267 +msgctxt "trusted-shops" +msgid "Variant" +msgstr "Variante" + +#: includes/class-wc-trusted-shops-admin.php:269 +msgctxt "trusted-shops" +msgid "You can display your Trustbadge with or without Review Stars." +msgstr "Du kannst dein Trustbadge mit oder ohne Bewertungssterne anzeigen." + +#: includes/class-wc-trusted-shops-admin.php:273 +#: includes/class-wc-trusted-shops-admin.php:763 +msgctxt "trusted-shops" +msgid "Display Trustbadge with review stars" +msgstr "Trustbadge mit Bewertungssternen anzeigen" + +#: includes/class-wc-trusted-shops-admin.php:274 +#: includes/class-wc-trusted-shops-admin.php:767 +msgctxt "trusted-shops" +msgid "Display Trustbadge without review stars" +msgstr "Trustbadge ohne Bewertungssterne anzeigen" + +#: includes/class-wc-trusted-shops-admin.php:280 +msgctxt "trusted-shops" +msgid "Vertical Offset" +msgstr "Vertikaler Abstand" + +#: includes/class-wc-trusted-shops-admin.php:281 +msgctxt "trusted-shops" +msgid "" +"Choose the distance that the Trustbadge will appear from the bottom-right " +"corner of the screen." +msgstr "" +"Wähle einen Abstand für dein Trustbadge vom unteren rechten Bildschirmrand." + +#: includes/class-wc-trusted-shops-admin.php:284 +#: includes/class-wc-trusted-shops-admin.php:492 +#: includes/class-wc-trusted-shops-admin.php:543 +#: includes/class-wc-trusted-shops-admin.php:558 +msgctxt "trusted-shops" +msgid "px" +msgstr "px" + +#: includes/class-wc-trusted-shops-admin.php:290 +#: includes/class-wc-trusted-shops-admin.php:499 +#: includes/class-wc-trusted-shops-admin.php:549 +#: includes/class-wc-trusted-shops-admin.php:565 +#, php-format +msgctxt "trusted-shops" +msgid "Please choose a non-negative number (at least %d)" +msgstr "Bitte verwende eine nicht-negative Nummer (mindestens %d)" + +#: includes/class-wc-trusted-shops-admin.php:296 +msgctxt "trusted-shops" +msgid "Trustbadge code" +msgstr "Trustbadge Code" + +#: includes/class-wc-trusted-shops-admin.php:308 +msgctxt "trusted-shops" +msgid "Configure your Shop Reviews" +msgstr "Konfiguriere deine Shopbewertungen" + +#: includes/class-wc-trusted-shops-admin.php:314 +msgctxt "trusted-shops" +msgid "Display Shop Review Sticker" +msgstr "Shopbewertungssticker anzeigen" + +#: includes/class-wc-trusted-shops-admin.php:315 +msgctxt "trusted-shops" +msgid "" +"To display the Shop Review Sticker, you have to assign the widget \"Trusted " +"Shops Review Sticker\"." +msgstr "" +"Um den Shopbewertungssticker anzuzeigen, musst du das Widget „Trusted Shops " +"Shopbewertungssticker“ zuweisen." + +#: includes/class-wc-trusted-shops-admin.php:316 +#, php-format +msgctxt "trusted-shops" +msgid "Assign widget %s" +msgstr "Widget %s zuweisen" + +#: includes/class-wc-trusted-shops-admin.php:316 +#: includes/class-wc-trusted-shops-admin.php:588 +#: includes/class-wc-trusted-shops-admin.php:896 +msgctxt "trusted-shops" +msgid "here" +msgstr "hier" + +#: includes/class-wc-trusted-shops-admin.php:324 +#: includes/class-wc-trusted-shops-admin.php:472 +msgctxt "trusted-shops" +msgid "Background color" +msgstr "Hintergrundfarbe" + +#: includes/class-wc-trusted-shops-admin.php:325 +msgctxt "trusted-shops" +msgid "Choose the background color for your Review Sticker." +msgstr "Wähle die Hintergrundfarbe für deinen Review Sticker." + +#: includes/class-wc-trusted-shops-admin.php:332 +msgctxt "trusted-shops" +msgid "Font" +msgstr "Schriftart" + +#: includes/class-wc-trusted-shops-admin.php:334 +msgctxt "trusted-shops" +msgid "Choose the font for your Review Sticker." +msgstr "Wähle die Schriftart für deinen Review Sticker." + +#: includes/class-wc-trusted-shops-admin.php:341 +msgctxt "trusted-shops" +msgid "Number of reviews displayed" +msgstr "Anzahl Bewertungen" + +#: includes/class-wc-trusted-shops-admin.php:342 +msgctxt "trusted-shops" +msgid "" +"Display x alternating Shop Reviews in your Shop Review Sticker. You can " +"display between 1 and 5 alternating Shop Reviews." +msgstr "" +"Zeige x Shopbewertungen im Wechsel in deinem Shopbewertungssticker an. Es " +"können mindestens 1 und maximal 5 Bewertungen im Wechsel angezeigt werden." + +#: includes/class-wc-trusted-shops-admin.php:345 +msgctxt "trusted-shops" +msgid "Show x alternating reviews" +msgstr "x Bewertungen im Wechsel zeigen" + +#: includes/class-wc-trusted-shops-admin.php:352 +#: includes/class-wc-trusted-shops-admin.php:369 +#, php-format +msgctxt "trusted-shops" +msgid "Please choose a non-negative number between %d and %d" +msgstr "Bitte verwende eine nicht-negative Nummer zwischen %d und %d" + +#: includes/class-wc-trusted-shops-admin.php:358 +msgctxt "trusted-shops" +msgid "Minimum rating displayed" +msgstr "Angezeigte Mindestnote" + +#: includes/class-wc-trusted-shops-admin.php:359 +msgctxt "trusted-shops" +msgid "Only show Shop Reviews with a minimum rating of x stars. " +msgstr "Zeige nur Shopbewertungen mit einer Mindestanzahl von x Sternen." + +#: includes/class-wc-trusted-shops-admin.php:362 +msgctxt "trusted-shops" +msgid "Star(s)" +msgstr "Stern(e)" + +#: includes/class-wc-trusted-shops-admin.php:375 +msgctxt "trusted-shops" +msgid "Sticker code" +msgstr "Sticker Code" + +#: includes/class-wc-trusted-shops-admin.php:379 +#: includes/class-wc-trusted-shops-admin.php:506 +#: includes/class-wc-trusted-shops-admin.php:571 +msgctxt "trusted-shops" +msgid "" +"The advanced configuration is for users with programming skills. Here you " +"can perform even more individual settings." +msgstr "" +"Der Expertenmodus ist für fortgeschrittene Nutzer mit Programmierkenntnissen " +"gedacht. Hier kannst du noch mehr individuelle Einstellungen vornehmen." + +#: includes/class-wc-trusted-shops-admin.php:385 +msgctxt "trusted-shops" +msgid "Google Organic Search" +msgstr "Organische Google Suche" + +#: includes/class-wc-trusted-shops-admin.php:386 +msgctxt "trusted-shops" +msgid "" +"Activate this option to give Google the opportunity to show your Shop " +"Reviews in Google organic search results." +msgstr "" +"Aktiviere diese Funktion, um Google die Möglichkeit zu geben, deine " +"Shopbewertungen in den organischen Google Suchergebnissen anzuzeigen." + +#: includes/class-wc-trusted-shops-admin.php:387 +msgctxt "trusted-shops" +msgid "" +"By activating this option, rich snippets will be integrated in the selected " +"pages so your shop review stars may be displayed in Google organic search " +"results. If you use Product Reviews and already activated rich snippets in " +"expert mode, we recommend integrating rich snippets for Shop Reviews on " +"category pages only." +msgstr "" +"Wenn du diese Option aktivierst, werden Rich Snippets in die ausgewählten " +"Seiten eingebunden, sodass deine Shopbewertungssterne in den organischen " +"Google Suchergebnissen angezeigt werden können. Wenn du Produktbewertungen " +"aktiviert hast und dort im Expertenmodus bereits Rich Snippets aktiviert " +"hast, empfehlen wir die Ausgabe der Rich Snippets für Shopbewertungen nur " +"auf der Kategorieseite." + +#: includes/class-wc-trusted-shops-admin.php:394 +msgctxt "trusted-shops" +msgid "Activate rich snippets on" +msgstr "Rich Snippets aktivieren auf" + +#: includes/class-wc-trusted-shops-admin.php:395 +msgctxt "trusted-shops" +msgid "category pages" +msgstr "Kategorieseiten" + +#: includes/class-wc-trusted-shops-admin.php:403 +msgctxt "trusted-shops" +msgid "product pages" +msgstr "Produktdetailseiten" + +#: includes/class-wc-trusted-shops-admin.php:411 +msgctxt "trusted-shops" +msgid "homepage (not recommended)" +msgstr "Startseite (nicht empfohlen)" + +#: includes/class-wc-trusted-shops-admin.php:419 +msgctxt "trusted-shops" +msgid "Rich snippets code" +msgstr "Rich Snippets Code" + +#: includes/class-wc-trusted-shops-admin.php:431 +msgctxt "trusted-shops" +msgid "Configure your Product Reviews " +msgstr "Konfiguriere deine Produktbewertungen" + +#: includes/class-wc-trusted-shops-admin.php:432 +#, php-format +msgctxt "trusted-shops" +msgid "To use Product Reviews, activate them in your %s first." +msgstr "" +"Um Produktbewertungen nutzen zu können, schalte diese zuerst in deinem %s " +"frei." + +#: includes/class-wc-trusted-shops-admin.php:432 +msgctxt "trusted-shops" +msgid "Trusted Shops package" +msgstr "Trusted Shops Paket" + +#: includes/class-wc-trusted-shops-admin.php:438 +msgctxt "trusted-shops" +msgid "Collect Product Reviews" +msgstr "Produktbewertungen sammeln" + +#: includes/class-wc-trusted-shops-admin.php:439 +msgctxt "trusted-shops" +msgid "" +"Show Product Reviews on the product page in a separate tab, just as shown on " +"the picture on the right." +msgstr "" +"Zeige Produktbewertungen auf der Produktseite in einem separaten Reiter, wie " +"in der Grafik rechts abgebildet." + +#: includes/class-wc-trusted-shops-admin.php:447 +msgctxt "trusted-shops" +msgid "Reviews" +msgstr "Bewertungen" + +#: includes/class-wc-trusted-shops-admin.php:448 +#: includes/class-wc-trusted-shops-admin.php:457 +msgctxt "trusted-shops" +msgid "You can choose a name for the tab with your Product Reviews." +msgstr "" +"Du kannst selbst bestimmen, wie der Reiter in dem deine Produktbewertungen " +"angezeigt werden, heißen soll." + +#: includes/class-wc-trusted-shops-admin.php:449 +msgctxt "trusted-shops" +msgid "Show Product Reviews on the product detail page in an additional tab." +msgstr "Produktbewertungen auf der Produktseite in separatem Reiter anzeigen." + +#: includes/class-wc-trusted-shops-admin.php:456 +msgctxt "trusted-shops" +msgid "Name of Product Reviews tab" +msgstr "Bezeichnung Reiter" + +#: includes/class-wc-trusted-shops-admin.php:460 +msgctxt "trusted-shops" +msgid "Product reviews" +msgstr "Produktbewertungen" + +#: includes/class-wc-trusted-shops-admin.php:464 +msgctxt "trusted-shops" +msgid "Border color" +msgstr "Umrandung" + +#: includes/class-wc-trusted-shops-admin.php:465 +msgctxt "trusted-shops" +msgid "Set the color for the frame around your Product Reviews." +msgstr "Lege die Farbe für den Rahmen um deine Produktbewertungen fest." + +#: includes/class-wc-trusted-shops-admin.php:473 +msgctxt "trusted-shops" +msgid "Set the background color for your Product Reviews." +msgstr "Lege die Hintergrundfarbe für deine Produktbewertungen fest." + +#: includes/class-wc-trusted-shops-admin.php:480 +#: includes/class-wc-trusted-shops-admin.php:530 +msgctxt "trusted-shops" +msgid "Star color" +msgstr "Farbe der Sterne" + +#: includes/class-wc-trusted-shops-admin.php:481 +msgctxt "trusted-shops" +msgid "Set the color for the Product Review stars in your Product Reviews tab." +msgstr "" +"Lege die Farbe der Sterne fest, die in deinem Produktbewertungs-Reiter " +"angezeigt werden. " + +#: includes/class-wc-trusted-shops-admin.php:488 +#: includes/class-wc-trusted-shops-admin.php:538 +msgctxt "trusted-shops" +msgid "Star size" +msgstr "Größe der Sterne" + +#: includes/class-wc-trusted-shops-admin.php:493 +msgctxt "trusted-shops" +msgid "Set the size for the Product Review stars in your Product Reviews tab." +msgstr "" +"Lege die Größe der Sterne fest, die in deinem Produktbewertungs-Reiter " +"angezeigt werden." + +#: includes/class-wc-trusted-shops-admin.php:504 +msgctxt "trusted-shops" +msgid "Product Sticker Code" +msgstr "Produktbewertungen Code" + +#: includes/class-wc-trusted-shops-admin.php:513 +#: includes/class-wc-trusted-shops-admin.php:579 +msgctxt "trusted-shops" +msgid "jQuerySelector" +msgstr "jQuerySelector" + +#: includes/class-wc-trusted-shops-admin.php:514 +msgctxt "trusted-shops" +msgid "" +"Please choose where your Product Reviews shall be displayed on the Product " +"detail page." +msgstr "" +"Wähle, wo die Produktbewertungen auf der Produktdetailseite angezeigt werden " +"sollen." + +#: includes/class-wc-trusted-shops-admin.php:521 +msgctxt "trusted-shops" +msgid "Rating stars" +msgstr "Bewertungssterne" + +#: includes/class-wc-trusted-shops-admin.php:522 +msgctxt "trusted-shops" +msgid "Show star ratings on the product detail page below your product name." +msgstr "Bewertungssterne auf der Produktseite unter dem Produktnamen anzeigen." + +#: includes/class-wc-trusted-shops-admin.php:523 +msgctxt "trusted-shops" +msgid "" +"Display Product Review stars on product pages below the product name, just " +"as shown in the picture on the right." +msgstr "" +"Zeige Bewertungssterne auf der Produktseite unter dem Produktnamen, wie in " +"der Grafik rechts abgebildet." + +#: includes/class-wc-trusted-shops-admin.php:532 +msgctxt "trusted-shops" +msgid "" +"Set the color for the review stars, that are displayed on the product page, " +"below your product name." +msgstr "" +"Lege die Farbe der Sterne fest, die auf der Produktseite unter deinem " +"Produktnamen angezeigt werden. " + +#: includes/class-wc-trusted-shops-admin.php:540 +msgctxt "trusted-shops" +msgid "" +"Set the size for the review stars that are displayed on the product page, " +"below your product name." +msgstr "" +"Lege die Größe der Sterne fest, die auf der Produktseite unter deinem " +"Produktnamen angezeigt werden." + +#: includes/class-wc-trusted-shops-admin.php:554 +msgctxt "trusted-shops" +msgid "Font size" +msgstr "Schriftgröße" + +#: includes/class-wc-trusted-shops-admin.php:556 +msgctxt "trusted-shops" +msgid "Set the font size for the text that goes with your review stars." +msgstr "Lege die Schriftgröße für den Text zu deinen Bewertungssternen fest." + +#: includes/class-wc-trusted-shops-admin.php:570 +msgctxt "trusted-shops" +msgid "Product Review Code" +msgstr "Produktbewertungen Code" + +#: includes/class-wc-trusted-shops-admin.php:580 +msgctxt "trusted-shops" +msgid "" +"Please choose where your Product Review Stars shall be displayed on the " +"Product Detail page." +msgstr "" +"Wähle, wo die Produktbewertungssterne auf der Produktdetailseite angezeigt " +"werden sollen." + +#: includes/class-wc-trusted-shops-admin.php:587 +msgctxt "trusted-shops" +msgid "Brand attribute" +msgstr "Marken-Produktattribut" + +#: includes/class-wc-trusted-shops-admin.php:588 +#, php-format +msgctxt "trusted-shops" +msgid "Create brand attribute %s" +msgstr "Marken-Produktattribut %s erstellen" + +#: includes/class-wc-trusted-shops-admin.php:589 +msgctxt "trusted-shops" +msgid "" +"Brand name of the product. By passing this information on to Google, you " +"improve your chances of having Google identify your products. Assign your " +"brand attribute. If your products don't have a GTIN, you can pass on the " +"brand name and the MPN to use Google Integration." +msgstr "" +"Markenname des Produkts. Durch Übergeben dieser Variable verbesserst du die " +"Möglichkeit deine Produkte von Google eindeutig identifizieren zu lassen. " +"Weise dein Marken-Produktattribut zu. Wenn deine Produkte keine GTIN haben, " +"kannst du den Markennamen zusammen mit der MPN übergeben, um die Google " +"Integration zu nutzen." + +#: includes/class-wc-trusted-shops-admin.php:595 +msgctxt "trusted-shops" +msgid "None" +msgstr "Keine" + +#: includes/class-wc-trusted-shops-admin.php:606 +msgctxt "trusted-shops" +msgid "Configure your Review Requests" +msgstr "Konfiguriere deine Bewertungserinnerungen" + +#: includes/class-wc-trusted-shops-admin.php:607 +msgctxt "trusted-shops" +msgid "" +"7 days after an order has been placed, Trusted Shops automatically sends an " +"invite to your customers. If you want to set a different time for sending " +"automatic Review Requests, please activate the option below. If you want to " +"send review requests with legal certainty, you need your customers' consent " +"to receive Review Requests. You also have to include an option to " +"unsubscribe." +msgstr "" +"Trusted Shops versendet 7 Tage nach Bestellung automatisch eine " +"Bewertungserinnerung an deinen Kunden. Wenn du lieber selbst entscheiden " +"möchtest, wann Bewertungsanfragen versendet werden, aktiviere die " +"untenstehende Option. Möchtest du rechtssicher Bewertungs-Erinnerungen " +"verschicken, so benötigst du die ausdrückliche Einwilligung deiner Kunden " +"zum Empfang von Bewertungsemails. Du musst deinen Kunden zudem eine " +"Möglichkeit geben, Bewertungserinnerungen wieder abzubestellen." + +#: includes/class-wc-trusted-shops-admin.php:613 +msgctxt "trusted-shops" +msgid "Enable Review Requests" +msgstr "Bewertungserinnerungen aktivieren" + +#: includes/class-wc-trusted-shops-admin.php:622 +msgctxt "trusted-shops" +msgid "WooCommerce status" +msgstr "Bestellstatus" + +#: includes/class-wc-trusted-shops-admin.php:623 +msgctxt "trusted-shops" +msgid "" +"We recommend choosing the order status that you set when your products have " +"been shipped." +msgstr "" +"Wähle hier am besten den Bestellstatus aus WooCommerce aus, den du " +"einstellst, wenn deine Ware versendet wurde." + +#: includes/class-wc-trusted-shops-admin.php:631 +msgctxt "trusted-shops" +msgid "Days until Review Request" +msgstr "Tage bis zur Erinnerung" + +#: includes/class-wc-trusted-shops-admin.php:632 +msgctxt "trusted-shops" +msgid "" +"Set the number of days to wait after an order has reached the order status " +"you selected above before having a review request sent to your customers." +msgstr "" +"Stelle hier ein nach wie vielen Tagen nach Erreichen des oben ausgewählten " +"Bestellstatus die Bewertungserinnerung an den Käufer versendet werden soll." + +#: includes/class-wc-trusted-shops-admin.php:644 +msgctxt "trusted-shops" +msgid "Permission via checkbox" +msgstr "Einwilligung per Checkbox" + +#: includes/class-wc-trusted-shops-admin.php:645 +msgctxt "trusted-shops" +msgid "" +"If the checkbox is activated, only customers who gave their consent will " +"receive Review Requests." +msgstr "" +"Bei aktivierter Checkbox erhalten nur die Kunden eine Bewertungserinnerung, " +"die ihr Einverständnis gegeben haben." + +#: includes/class-wc-trusted-shops-admin.php:649 +msgctxt "trusted-shops" +msgid "Edit checkbox" +msgstr "Checkbox anpassen" + +#: includes/class-wc-trusted-shops-admin.php:653 +msgctxt "trusted-shops" +msgid "Unsubscribe via link" +msgstr "Abmeldung per Link" + +#: includes/class-wc-trusted-shops-admin.php:654 +msgctxt "trusted-shops" +msgid "Allows the customer to unsubscribe from Review Requests." +msgstr "" +"Erlaubt es dem Kunden sich von Bewertungserinnerungen per Link abzumelden." + +#: includes/class-wc-trusted-shops-admin.php:755 +msgctxt "trusted-shops" +msgid "How does Trusted Shops make your shop better?" +msgstr "Wie macht Trusted Shops deinen Shop besser?" + +#: includes/class-wc-trusted-shops-admin.php:757 +msgctxt "trusted-shops" +msgid "Get your account" +msgstr "Erstelle deinen Account" + +#: includes/class-wc-trusted-shops-admin.php:777 +msgctxt "trusted-shops" +msgid "Product Reviews on the product detail page in an additional tab" +msgstr "Produktbewertungen auf der Produktseite in einem separatem Reiter" + +#: includes/class-wc-trusted-shops-admin.php:780 +msgctxt "trusted-shops" +msgid "Show Star-Ratings on the product detail page below your product name" +msgstr "Bewertungssterne unter dem Produktnamen auf der Produktseite" + +#: includes/class-wc-trusted-shops-admin.php:784 +msgctxt "trusted-shops" +msgid "" +"Please note: If you want to send review requests through WooCommerce, you " +"should deactivate automated review requests through Trusted Shops. To do so, " +"please go to your My Trusted Shops account. Log in and go to Reviews > " +"Settings and deactivate \"Collect reviews automatically\"" +msgstr "" +"Bitte beachte: Wenn du Bewertungserinnerungen über WooCommerce versenden " +"möchtest, solltest du den Versand von automatischen Bewertungserinnerungen " +"über Trusted Shops deaktivieren. Gehe dazu in deinen My Trusted Shops " +"Account. Logge dich ein und gehe zu Bewertungen > Konfiguration und " +"deaktiviere dort „Bewertungen automatisch sammeln“." + +#: includes/class-wc-trusted-shops-admin.php:785 +msgctxt "trusted-shops" +msgid "To your My Trusted Shops account" +msgstr "Zu deinem My Trusted Shops Account" + +#: includes/class-wc-trusted-shops-admin.php:789 +msgctxt "trusted-shops" +msgid "" +"Export your customer information here and upload it in the Trusted Shops " +"Review Collector. To do so go to your My Trusted Shops account. Log in and " +"go to Reviews > Shop Reviews > Review Collector" +msgstr "" +"Exportiere hier die Kundendaten und lade diese im Trusted Shops Review " +"Collector hoch. Gehe dazu in deinen My Trusted Shops Account. Logge dich ein " +"und gehe zu Bewertungen > Shopbewertungen > Review Collector" + +#: includes/class-wc-trusted-shops-admin.php:790 +msgctxt "trusted-shops" +msgid "To the Trusted Shops Review Collector" +msgstr "Zum Trusted Shops Review Collector" + +#: includes/class-wc-trusted-shops-admin.php:880 +msgctxt "trusted-shops" +msgid "Review Collector" +msgstr "Review Collector" + +#: includes/class-wc-trusted-shops-admin.php:882 +#, php-format +msgctxt "trusted-shops" +msgid "" +"Want to collect reviews for orders that were placed before your Trusted " +"Shops Integration? No problem. Export old orders here and upload them in " +"your %s." +msgstr "" +"Du möchtest nachträglich Bewertungen zu Bestellungen sammeln, die vor der " +"Trusted Shops Integration getätigt wurden? Kein Problem. Exportiere alte " +"Bestellungen hier und lade diese in deinem %s hoch." + +#: includes/class-wc-trusted-shops-admin.php:882 +msgctxt "trusted-shops" +msgid "My Trusted Shops account" +msgstr "My Trusted Shops Account" + +#: includes/class-wc-trusted-shops-admin.php:888 +msgctxt "trusted-shops" +msgid "Export orders" +msgstr "Bestellungen exportieren" + +#: includes/class-wc-trusted-shops-admin.php:888 +msgctxt "trusted-shops" +msgid "" +"Export your customer and order information of the last x days and upload " +"them in your My Trusted Shops Account." +msgstr "" +"Exportiere deine Kunden- und Bestelldaten der letzten x Tage und lade diese " +"in deinem My Trusted Shops Account hoch." + +#: includes/class-wc-trusted-shops-admin.php:892 +msgctxt "trusted-shops" +msgid "30 days" +msgstr "30 Tage" + +#: includes/class-wc-trusted-shops-admin.php:893 +msgctxt "trusted-shops" +msgid "60 days" +msgstr "60 Tage" + +#: includes/class-wc-trusted-shops-admin.php:894 +msgctxt "trusted-shops" +msgid "90 days" +msgstr "90 Tage" + +#: includes/class-wc-trusted-shops-admin.php:896 +#, php-format +msgctxt "trusted-shops" +msgid "Upload customer and order information %s." +msgstr "Kunden- und Bestelldaten %s hochladen" + +#: includes/class-wc-trusted-shops-admin.php:899 +msgctxt "trusted-shops" +msgid "Days until reminder mail" +msgstr "Tage bis zur Erinnerung" + +#: includes/class-wc-trusted-shops-admin.php:899 +msgctxt "trusted-shops" +msgid "" +"Set the number of days to wait after the order date before having a Review " +"Request sent to your customers." +msgstr "" +"Stelle hier ein, wie viele Tage zwischen der Bestellung und dem Versand der " +"Bewertungserinnerung liegen soll." + +#: includes/class-wc-trusted-shops-admin.php:903 +msgctxt "trusted-shops" +msgid "Start export" +msgstr "Export starten" + +#: includes/class-wc-trusted-shops-core.php:55 +#: includes/class-wc-trusted-shops-core.php:64 +#: includes/class-wc-ts-dependencies.php:36 +#: includes/class-wc-ts-dependencies.php:45 +msgctxt "trusted-shops" +msgid "Cheatin’ huh?" +msgstr "So geht das leider nicht.." + +#: includes/class-wc-trusted-shops-core.php:213 +msgctxt "trusted-shops" +msgid "Yes" +msgstr "Ja" + +#: includes/class-wc-trusted-shops-core.php:213 +msgctxt "trusted-shops" +msgid "No" +msgstr "Nein" + +#: includes/class-wc-trusted-shops-core.php:261 +#, php-format +msgctxt "trusted-shops" +msgid "" +"If the App helped you, please leave a %s★★" +"★★★%s in the Wordpress plugin repository." +msgstr "" +"Wenn dir die App hilft, hinterlasse bitte eine %s★" +"★★★★%s Bewertung in der WordPress Plugin Bibliothek." + +#: includes/class-wc-trusted-shops-core.php:410 +msgctxt "trusted-shops" +msgid "Settings" +msgstr "Einstellungen" + +#: includes/class-wc-trusted-shops-review-exporter.php:64 +msgctxt "trusted-shops" +msgid "Order ID" +msgstr "Bestellnummer" + +#: includes/class-wc-trusted-shops-review-exporter.php:65 +msgctxt "trusted-shops" +msgid "Order date" +msgstr "Bestelldatum" + +#: includes/class-wc-trusted-shops-review-exporter.php:66 +msgctxt "trusted-shops" +msgid "# Days" +msgstr "# Tage" + +#: includes/class-wc-trusted-shops-review-exporter.php:67 +msgctxt "trusted-shops" +msgid "Email" +msgstr "E-Mail" + +#: includes/class-wc-trusted-shops-review-exporter.php:68 +msgctxt "trusted-shops" +msgid "First name" +msgstr "Vorname" + +#: includes/class-wc-trusted-shops-review-exporter.php:69 +msgctxt "trusted-shops" +msgid "Last name" +msgstr "Nachname" + +#: includes/class-wc-trusted-shops-template-hooks.php:121 +#, php-format +msgctxt "trusted-shops" +msgid "" +"Your review reminder e-mail has been cancelled successfully. Return to %s." +msgstr "" +"Deine Bewertungserinnerung wurde erfolgreich deaktiviert. Kehre zurück zur " +"%s." + +#: includes/class-wc-trusted-shops-template-hooks.php:121 +msgctxt "trusted-shops" +msgid "Home" +msgstr "Startseite" + +#: includes/class-wc-trusted-shops-template-hooks.php:193 +msgctxt "trusted-shops" +msgid "" +"Yes, I would like to be reminded via e-mail after {days} day(s) to review my " +"order. I am able to cancel the reminder at any time by clicking on the " +"\"cancel review reminder\" link within the order confirmation." +msgstr "" +"Ja, ich bin damit einverstanden, eine Erinnerung per E-Mail zur Bewertung " +"nach {days} Tage(n) zu erhalten. Ich kann mich jederzeit davon abmelden bzw. " +"widersprechen, indem ich dem Link „von der Bewertungserinnerung abmelden“ in " +"der Bestellbestätigung folge." + +#: includes/class-wc-trusted-shops-template-hooks.php:198 +msgctxt "trusted-shops" +msgid "Please allow us to send a review reminder by e-mail." +msgstr "Bitte akzeptiere den Erhalt einer Bewertungserinnerung per E-Mail." + +#: includes/class-wc-trusted-shops-template-hooks.php:201 +msgctxt "trusted-shops" +msgid "Review reminder" +msgstr "Bewertungs Erinnerung" + +#: includes/class-wc-trusted-shops-template-hooks.php:202 +msgctxt "trusted-shops" +msgid "Asks the customer to receive a Trusted Shops review reminder." +msgstr "" +"Holt die Erlaubnis zum Senden einer einmaligen Trusted Shops " +"Bewertungserinnerung ein." + +#: includes/emails/class-wc-ts-email-customer-trusted-shops.php:24 +msgctxt "trusted-shops" +msgid "Trusted Shops Review Reminder" +msgstr "Trusted Shops Bewertungs-Erinnerung" + +#: includes/emails/class-wc-ts-email-customer-trusted-shops.php:25 +msgctxt "trusted-shops" +msgid "" +"This E-Mail is being sent to a customer to remind him about the possibility " +"to leave a review at Trusted Shops." +msgstr "" +"Diese E-Mail wird einmalig an Kunden verschickt, um diese an die Abgabe " +"einer Bewertung bei Trusted Shops zu erinnern." + +#: includes/emails/class-wc-ts-email-customer-trusted-shops.php:54 +msgctxt "trusted-shops" +msgid "Please rate your {site_title} order from {order_date}" +msgstr "Bitte bewerte deinen Einkauf vom {order_date} bei {site_title}" + +#: includes/emails/class-wc-ts-email-customer-trusted-shops.php:64 +msgctxt "trusted-shops" +msgid "Please rate your Order" +msgstr "Bitte bewerte deinen Einkauf" + +#: includes/widgets/class-wc-trusted-shops-widget-review-sticker.php:19 +msgctxt "trusted-shops" +msgid "Show your TS shop review sticker." +msgstr "Zeige deinen Trusted Shops Review Sticker an." + +#: includes/widgets/class-wc-trusted-shops-widget-review-sticker.php:21 +msgctxt "trusted-shops" +msgid "Trusted Shops Shop Review Sticker" +msgstr "Trusted Shops Shop Review Sticker" + +#: includes/widgets/class-wc-trusted-shops-widget-review-sticker.php:25 +#: includes/widgets/class-wc-trusted-shops-widget-review-sticker.php:46 +msgctxt "trusted-shops" +msgid "Trusted Shops Reviews" +msgstr "Trusted Shops Bewertung" + +#: includes/widgets/class-wc-trusted-shops-widget-review-sticker.php:26 +msgctxt "trusted-shops" +msgid "Title" +msgstr "Bezeichnung" + +#: src/Package.php:55 +msgctxt "trusted-shops" +msgid "" +"Trustbadge Reviews for WooCommerce needs at least WooCommerce version 3.1 to " +"run." +msgstr "" +"Trustbadge Reviews for WooCommerce benötigt mind. WooCommerce Version 3.1 um " +"zu starten." + +#: templates/emails/customer-trusted-shops.php:17 +#: templates/emails/plain/customer-trusted-shops.php:14 +#, php-format +msgctxt "trusted-shops" +msgid "Dear %s %s," +msgstr "Hallo %s %s," + +#: templates/emails/customer-trusted-shops.php:18 +#: templates/emails/plain/customer-trusted-shops.php:16 +#, php-format +msgctxt "trusted-shops" +msgid "" +"You have recently shopped at %s. Thank you! We would be glad if you spent " +"some time to write a review about your order. To do so please follow follow " +"the link." +msgstr "" +"Du hast vor einiger Zeit bei %s eingekauft. Vielen Dank! Wir wären froh " +"darüber, wenn du dir die Zeit nimmst und deinen Einkauf bewerten würdest. Um " +"dies nun zu tun, klicke bitte auf den nachfolgenden Link." + +#: templates/emails/customer-trusted-shops.php:22 +msgctxt "trusted-shops" +msgid "Rate Order now" +msgstr "Einkauf jetzt bewerten" + +#~ msgctxt "trusted-shops" +#~ msgid "Duplicate Plugin installation" +#~ msgstr "Doppelte Plugin Installation" + +#, php-format +#~ msgctxt "trusted-shops" +#~ msgid "" +#~ "It seems like you've installed WooCommerce Germanized and Trustbadge " +#~ "Reviews for WooCommerce. Please deactivate Trustbadge Reviews for " +#~ "WooCommerce as long as you are using WooCommerce Germanized. You can " +#~ "manage your Trusted Shops configuration within your %s." +#~ msgstr "" +#~ "Es scheint als hättest du WooCommerce Germanized und Trustbadge Reviews " +#~ "for WooCommerce installiert. Bitte deaktiviere das Trustbadge Reviews " +#~ "Plugin solange du WooCommerce Germanized verwendest. Du kannst deine " +#~ "Trusted Shops Konfiguration in deinen %s verwalten." + +#~ msgctxt "trusted-shops" +#~ msgid "Germanized settings" +#~ msgstr "Germanized Einstellungen" + +#~ msgctxt "trusted-shops" +#~ msgid "Deactivate standalone version" +#~ msgstr "Deaktiviere die Standalone-Version" + +#~ msgctxt "trusted-shops" +#~ msgid "(WooCommerce Product Reviews will be replaced)" +#~ msgstr "(WooCommerce Produktbewertungen werden ersetzt)" + +#, php-format +#~ msgid "" +#~ "Please install WooCommerce before " +#~ "installing WooCommerce Germanized. Thank you!" +#~ msgstr "" +#~ "Bitte installiere WooCommerce bevor " +#~ "du WooCommerce Germanized installierst. Vielen Dank!" diff --git a/packages/woocommerce-trusted-shops/i18n/languages/woocommerce-trusted-shops-de_DE_formal.mo b/packages/woocommerce-trusted-shops/i18n/languages/woocommerce-trusted-shops-de_DE_formal.mo new file mode 100644 index 0000000000000000000000000000000000000000..4ea14e41aece4d4354ff74c4781aa66c780b6b77 GIT binary patch literal 25805 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 sH3_jNDOK3O-;Pn-Hq)$ literal 0 HcmV?d00001 diff --git a/packages/woocommerce-trusted-shops/i18n/languages/woocommerce-trusted-shops-de_DE_formal.po b/packages/woocommerce-trusted-shops/i18n/languages/woocommerce-trusted-shops-de_DE_formal.po new file mode 100644 index 000000000..1b18aea99 --- /dev/null +++ b/packages/woocommerce-trusted-shops/i18n/languages/woocommerce-trusted-shops-de_DE_formal.po @@ -0,0 +1,1172 @@ +msgid "" +msgstr "" +"Project-Id-Version: WooCommerce Trusted Shops\n" +"POT-Creation-Date: 2019-10-15 12:40+0200\n" +"PO-Revision-Date: 2019-10-15 12:41+0200\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 2.2.4\n" +"X-Poedit-Basepath: ../..\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Poedit-KeywordsList: __;_e;__ngettext:1,2;_n:1,2;__ngettext_noop:1,2;" +"_n_noop:1,2;_c,_nc:4c,1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;_nx_noop:4c,1,2;" +"esc_attr_e;esc_html_e;esc_html__\n" +"X-Poedit-SearchPath-0: .\n" +"X-Poedit-SearchPathExcluded-0: node_modules\n" +"X-Poedit-SearchPathExcluded-1: vendor\n" + +#: includes/admin/settings/class-wc-ts-gzd-settings-tab.php:48 +msgctxt "trusted-shops" +msgid "Setup your Trusted Shops Integration." +msgstr "Setzen Sie Ihre Trusted Shops Integration auf." + +#: includes/admin/settings/class-wc-ts-gzd-settings-tab.php:52 +#: includes/class-wc-ts-settings-handler.php:23 +msgctxt "trusted-shops" +msgid "Trusted Shops" +msgstr "Trusted Shops" + +#: includes/admin/views/html-notice-dependencies.php:16 +msgctxt "trusted-shops" +msgid "Dependencies Missing or Outdated" +msgstr "Wichtige Plugins fehlen oder sind veraltet" + +#: includes/admin/views/html-notice-dependencies.php:24 +msgctxt "trusted-shops" +msgid "" +"To use WooCommerce Trusted Shops you may at first install the following " +"plugins:" +msgstr "" +"Um WooCommerce Trusted Shops zuverlässig nutzen zu können, müssen Sie zuerst " +"folgende Plugins installieren:" + +#: includes/admin/views/html-notice-dependencies.php:28 +#, php-format +msgctxt "trusted-shops" +msgid "Install %s" +msgstr "Installiere %s" + +#: includes/admin/views/html-notice-dependencies.php:36 +msgctxt "trusted-shops" +msgid "" +"To use WooCommerce Trusted Shops you may at first update the following " +"plugins to a newer version:" +msgstr "" +"Um WooCommerce Trusted Shops zuverlässig nutzen zu können, updaten Sie bitte " +"folgende Plugins:" + +#: includes/admin/views/html-notice-dependencies.php:40 +#, php-format +msgctxt "trusted-shops" +msgid "%s required in at least version %s" +msgstr "%s wird mindestens in Version %s benötigt" + +#: includes/admin/views/html-notice-dependencies.php:49 +msgctxt "trusted-shops" +msgid "Check for Updates" +msgstr "nach Updates suchen" + +#: includes/admin/views/html-notice-dependencies.php:50 +msgctxt "trusted-shops" +msgid "or" +msgstr "oder" + +#: includes/admin/views/html-notice-dependencies.php:51 +msgctxt "trusted-shops" +msgid "Install an older version" +msgstr "Installiere eine ältere Version" + +#: includes/admin/views/html-notice-update.php:14 +msgctxt "trusted-shops" +msgid "" +"WooCommerce Trusted Shops Data Update Required – We " +"just need to update your installation to the latest version" +msgstr "" +"WooCommerce Trusted Shops Datenaktualisierung erforderlich " +"– Wir müssen deine Installation auf die neueste Version updaten" + +#: includes/admin/views/html-notice-update.php:15 +msgctxt "trusted-shops" +msgid "Run the updater" +msgstr "Update starten" + +#: includes/admin/views/html-notice-update.php:19 +msgctxt "trusted-shops" +msgid "" +"It is strongly recommended that you backup your database before proceeding. " +"Are you sure you wish to run the updater now?" +msgstr "" +"Sie sollten vor einem Update immer ein Backup der Datenbank anlegen. Sind " +"Sie sicher das Update jetzt zu installieren?" + +#: includes/admin/views/html-wpml-notice.php:11 +msgctxt "trusted-shops" +msgid "WPML Support" +msgstr "WPML Unterstützung" + +#: includes/admin/views/html-wpml-notice.php:14 +msgctxt "trusted-shops" +msgid "" +"These settings serve as default settings for all your languages. To adjust " +"the settings for a certain language, please switch your admin language " +"through the WPML language switcher and adjust the corresponding settings." +msgstr "" +"Diese Einstellungen werden als Standard für alle Ihre Sprachen verwendet. Um " +"die Einstellungen für eine spezielle Sprache zu ändern, wechseln Sie bitte " +"zur entsprechenden Sprache über den WPML Sprachumschalter." + +#: includes/admin/views/html-wpml-notice.php:16 +#, php-format +msgctxt "trusted-shops" +msgid "" +"These settings apply for your %s shop. To adjust settings for another " +"language, please switch your admin language through the WPML language " +"switcher." +msgstr "" +"Diese Einstellungen werden für Ihren %s Shop verwendet. Um die Einstellungen " +"für eine andere Sprache anzupassen, wechseln Sie bitte die Sprache über den " +"WPML Sprachumschalter." + +#: includes/class-wc-trusted-shops-admin.php:84 +#: includes/class-wc-trusted-shops-admin.php:121 +msgctxt "trusted-shops" +msgid "GTIN" +msgstr "GTIN" + +#: includes/class-wc-trusted-shops-admin.php:84 +#: includes/class-wc-trusted-shops-admin.php:121 +msgctxt "trusted-shops" +msgid "" +"ID that allows your products to be identified worldwide. If you want to " +"display your Trusted Shops Product Reviews in Google Shopping and paid " +"Google adverts, Google needs the GTIN." +msgstr "" +"Identifikationsnummer, mit der Produkte weltweit eindeutig identifiziert " +"werden können. Wenn Sie Ihre Trusted Shops Produktbewertungen in Google " +"Shopping und bezahlten Google Produktanzeigen ausspielen möchten, benötigt " +"Google die GTIN." + +#: includes/class-wc-trusted-shops-admin.php:88 +#: includes/class-wc-trusted-shops-admin.php:122 +msgctxt "trusted-shops" +msgid "MPN" +msgstr "MPN" + +#: includes/class-wc-trusted-shops-admin.php:88 +#: includes/class-wc-trusted-shops-admin.php:122 +msgctxt "trusted-shops" +msgid "" +"If you don't have a GTIN for your products, you can pass the brand name and " +"the MPN on to Google to use the Trusted Shops Google Integration." +msgstr "" +"Wenn Ihre Produkte keine GTIN haben, können SIe den Markennamen zusammen mit " +"der MPN übergeben, um die Trusted Shops Google Integration zu nutzen." + +#: includes/class-wc-trusted-shops-admin.php:142 +msgctxt "trusted-shops" +msgid "Brand" +msgstr "Marke" + +#: includes/class-wc-trusted-shops-admin.php:176 +msgctxt "trusted-shops" +msgid "This field is mandatory" +msgstr "Dieses Feld ist ein Pflichtfeld" + +#: includes/class-wc-trusted-shops-admin.php:183 +msgctxt "trusted-shops" +msgid "Trusted Shops Options" +msgstr "Trusted Shops" + +#: includes/class-wc-trusted-shops-admin.php:190 +msgctxt "trusted-shops" +msgid "Arial" +msgstr "Arial" + +#: includes/class-wc-trusted-shops-admin.php:191 +msgctxt "trusted-shops" +msgid "Geneva" +msgstr "Geneva" + +#: includes/class-wc-trusted-shops-admin.php:192 +msgctxt "trusted-shops" +msgid "Georgia" +msgstr "Georgia" + +#: includes/class-wc-trusted-shops-admin.php:193 +msgctxt "trusted-shops" +msgid "Helvetica" +msgstr "Helvetica" + +#: includes/class-wc-trusted-shops-admin.php:194 +msgctxt "trusted-shops" +msgid "Sans-serif" +msgstr "Sans-serif" + +#: includes/class-wc-trusted-shops-admin.php:195 +msgctxt "trusted-shops" +msgid "Serif" +msgstr "Serif" + +#: includes/class-wc-trusted-shops-admin.php:196 +msgctxt "trusted-shops" +msgid "Trebuchet MS" +msgstr "Trebuchet MS" + +#: includes/class-wc-trusted-shops-admin.php:197 +msgctxt "trusted-shops" +msgid "Verdana" +msgstr "Verdana" + +#: includes/class-wc-trusted-shops-admin.php:220 +msgctxt "trusted-shops" +msgid "Trusted Shops Integration" +msgstr "Trusted Shops Integration" + +#: includes/class-wc-trusted-shops-admin.php:221 +#, php-format +msgctxt "trusted-shops" +msgid "Do you need help with integrating your Trustbadge? %s" +msgstr "Brauchen Sie Hilfe bei der Einbindung Ihres Trustbadges? %s" + +#: includes/class-wc-trusted-shops-admin.php:221 +msgctxt "trusted-shops" +msgid "To the step-by-step instructions" +msgstr "Zur Schritt-für-Schritt Anleitung" + +#: includes/class-wc-trusted-shops-admin.php:227 +msgctxt "trusted-shops" +msgid "Trusted Shops ID" +msgstr "Trusted Shops ID" + +#: includes/class-wc-trusted-shops-admin.php:228 +msgctxt "trusted-shops" +msgid "" +"The Trusted Shops ID is a unique identifier for your shop. You can find your " +"Trusted Shops ID in your My Trusted Shops account." +msgstr "" +"Die Trusted Shops ID identifiziert Ihren Shop eindeutig bei Trusted Shops. " +"Sie finden die Trusted Shops ID in Ihrem My Trusted Shops Account." + +#: includes/class-wc-trusted-shops-admin.php:237 +msgctxt "trusted-shops" +msgid "Edit Mode" +msgstr "Bearbeitungsmodus" + +#: includes/class-wc-trusted-shops-admin.php:239 +#: includes/class-wc-trusted-shops-admin.php:300 +#: includes/class-wc-trusted-shops-admin.php:423 +msgctxt "trusted-shops" +msgid "" +"The advanced configuration is for users with programming skills. Here you " +"can create even more individual settings." +msgstr "" +"Der Expertenmodus ist für fortgeschrittene Nutzer mit Programmierkenntnissen " +"gedacht. Hier können Sie noch mehr individuelle Einstellungen vornehmen." + +#: includes/class-wc-trusted-shops-admin.php:243 +msgctxt "trusted-shops" +msgid "Standard configuration" +msgstr "Standardmodus" + +#: includes/class-wc-trusted-shops-admin.php:244 +msgctxt "trusted-shops" +msgid "Advanced configuration" +msgstr "Expertenmodus" + +#: includes/class-wc-trusted-shops-admin.php:252 +msgctxt "trusted-shops" +msgid "Configure your Trustbadge" +msgstr "Konfigurieren Sie Ihr Trustbadge" + +#: includes/class-wc-trusted-shops-admin.php:258 +msgctxt "trusted-shops" +msgid "Display Trustbadge" +msgstr "Trustbadge anzeigen" + +#: includes/class-wc-trusted-shops-admin.php:260 +msgctxt "trusted-shops" +msgid "Display the Trustbadge on all the pages of your shop." +msgstr "Zeige das Trustbadge auf allen Seiten des Shops an." + +#: includes/class-wc-trusted-shops-admin.php:267 +msgctxt "trusted-shops" +msgid "Variant" +msgstr "Variante" + +#: includes/class-wc-trusted-shops-admin.php:269 +msgctxt "trusted-shops" +msgid "You can display your Trustbadge with or without Review Stars." +msgstr "Sie können Ihr Trustbadge mit oder ohne Bewertungssterne anzeigen." + +#: includes/class-wc-trusted-shops-admin.php:273 +#: includes/class-wc-trusted-shops-admin.php:763 +msgctxt "trusted-shops" +msgid "Display Trustbadge with review stars" +msgstr "Trustbadge mit Bewertungssternen anzeigen" + +#: includes/class-wc-trusted-shops-admin.php:274 +#: includes/class-wc-trusted-shops-admin.php:767 +msgctxt "trusted-shops" +msgid "Display Trustbadge without review stars" +msgstr "Trustbadge ohne Bewertungssterne anzeigen" + +#: includes/class-wc-trusted-shops-admin.php:280 +msgctxt "trusted-shops" +msgid "Vertical Offset" +msgstr "Vertikaler Abstand" + +#: includes/class-wc-trusted-shops-admin.php:281 +msgctxt "trusted-shops" +msgid "" +"Choose the distance that the Trustbadge will appear from the bottom-right " +"corner of the screen." +msgstr "" +"Wählen Sie einen Abstand für Ihr Trustbadge vom unteren rechten " +"Bildschirmrand." + +#: includes/class-wc-trusted-shops-admin.php:284 +#: includes/class-wc-trusted-shops-admin.php:492 +#: includes/class-wc-trusted-shops-admin.php:543 +#: includes/class-wc-trusted-shops-admin.php:558 +msgctxt "trusted-shops" +msgid "px" +msgstr "px" + +#: includes/class-wc-trusted-shops-admin.php:290 +#: includes/class-wc-trusted-shops-admin.php:499 +#: includes/class-wc-trusted-shops-admin.php:549 +#: includes/class-wc-trusted-shops-admin.php:565 +#, php-format +msgctxt "trusted-shops" +msgid "Please choose a non-negative number (at least %d)" +msgstr "Bitte verwenden Sie eine nicht-negative Nummer (mindestens %d)" + +#: includes/class-wc-trusted-shops-admin.php:296 +msgctxt "trusted-shops" +msgid "Trustbadge code" +msgstr "Trustbadge Code" + +#: includes/class-wc-trusted-shops-admin.php:308 +msgctxt "trusted-shops" +msgid "Configure your Shop Reviews" +msgstr "Konfigurieren Sie Ihre Shopbewertungen" + +#: includes/class-wc-trusted-shops-admin.php:314 +msgctxt "trusted-shops" +msgid "Display Shop Review Sticker" +msgstr "Shopbewertungssticker anzeigen" + +#: includes/class-wc-trusted-shops-admin.php:315 +msgctxt "trusted-shops" +msgid "" +"To display the Shop Review Sticker, you have to assign the widget \"Trusted " +"Shops Review Sticker\"." +msgstr "" +"Um den Shopbewertungssticker anzuzeigen, müssen Sie das Widget „Trusted " +"Shops Shopbewertungssticker“ zuweisen." + +#: includes/class-wc-trusted-shops-admin.php:316 +#, php-format +msgctxt "trusted-shops" +msgid "Assign widget %s" +msgstr "Widget %s zuweisen" + +#: includes/class-wc-trusted-shops-admin.php:316 +#: includes/class-wc-trusted-shops-admin.php:588 +#: includes/class-wc-trusted-shops-admin.php:896 +msgctxt "trusted-shops" +msgid "here" +msgstr "hier" + +#: includes/class-wc-trusted-shops-admin.php:324 +#: includes/class-wc-trusted-shops-admin.php:472 +msgctxt "trusted-shops" +msgid "Background color" +msgstr "Hintergrundfarbe" + +#: includes/class-wc-trusted-shops-admin.php:325 +msgctxt "trusted-shops" +msgid "Choose the background color for your Review Sticker." +msgstr "Wählen Sie die Hintergrundfarbe für den Review Sticker." + +#: includes/class-wc-trusted-shops-admin.php:332 +msgctxt "trusted-shops" +msgid "Font" +msgstr "Schriftart" + +#: includes/class-wc-trusted-shops-admin.php:334 +msgctxt "trusted-shops" +msgid "Choose the font for your Review Sticker." +msgstr "Wählen Sie die Schriftart für den Review Sticker." + +#: includes/class-wc-trusted-shops-admin.php:341 +msgctxt "trusted-shops" +msgid "Number of reviews displayed" +msgstr "Anzahl Bewertungen" + +#: includes/class-wc-trusted-shops-admin.php:342 +msgctxt "trusted-shops" +msgid "" +"Display x alternating Shop Reviews in your Shop Review Sticker. You can " +"display between 1 and 5 alternating Shop Reviews." +msgstr "" +"Zeige x Shopbewertungen im Wechsel in Ihrem Shopbewertungssticker an. Es " +"können mindestens 1 und maximal 5 Bewertungen im Wechsel angezeigt werden." + +#: includes/class-wc-trusted-shops-admin.php:345 +msgctxt "trusted-shops" +msgid "Show x alternating reviews" +msgstr "x Bewertungen im Wechsel zeigen" + +#: includes/class-wc-trusted-shops-admin.php:352 +#: includes/class-wc-trusted-shops-admin.php:369 +#, php-format +msgctxt "trusted-shops" +msgid "Please choose a non-negative number between %d and %d" +msgstr "Bitte verwenden Sie eine nicht-negative Nummer zwischen %d und %d" + +#: includes/class-wc-trusted-shops-admin.php:358 +msgctxt "trusted-shops" +msgid "Minimum rating displayed" +msgstr "Angezeigte Mindestnote" + +#: includes/class-wc-trusted-shops-admin.php:359 +msgctxt "trusted-shops" +msgid "Only show Shop Reviews with a minimum rating of x stars. " +msgstr "Zeige nur Shopbewertungen mit einer Mindestanzahl von x Sternen." + +#: includes/class-wc-trusted-shops-admin.php:362 +msgctxt "trusted-shops" +msgid "Star(s)" +msgstr "Stern(e)" + +#: includes/class-wc-trusted-shops-admin.php:375 +msgctxt "trusted-shops" +msgid "Sticker code" +msgstr "Sticker Code" + +#: includes/class-wc-trusted-shops-admin.php:379 +#: includes/class-wc-trusted-shops-admin.php:506 +#: includes/class-wc-trusted-shops-admin.php:571 +msgctxt "trusted-shops" +msgid "" +"The advanced configuration is for users with programming skills. Here you " +"can perform even more individual settings." +msgstr "" +"Der Expertenmodus ist für fortgeschrittene Nutzer mit Programmierkenntnissen " +"gedacht. Hier können Sie noch mehr individuelle Einstellungen vornehmen." + +#: includes/class-wc-trusted-shops-admin.php:385 +msgctxt "trusted-shops" +msgid "Google Organic Search" +msgstr "Organische Google Suche" + +#: includes/class-wc-trusted-shops-admin.php:386 +msgctxt "trusted-shops" +msgid "" +"Activate this option to give Google the opportunity to show your Shop " +"Reviews in Google organic search results." +msgstr "" +"Aktivieren Sie diese Funktion, um Google die Möglichkeit zu geben, Ihre " +"Shopbewertungen in den organischen Google Suchergebnissen anzuzeigen." + +#: includes/class-wc-trusted-shops-admin.php:387 +msgctxt "trusted-shops" +msgid "" +"By activating this option, rich snippets will be integrated in the selected " +"pages so your shop review stars may be displayed in Google organic search " +"results. If you use Product Reviews and already activated rich snippets in " +"expert mode, we recommend integrating rich snippets for Shop Reviews on " +"category pages only." +msgstr "" +"Wenn Sie diese Option aktivieren, werden Rich Snippets in die ausgewählten " +"Seiten eingebunden, sodass Ihre Shopbewertungssterne in den organischen " +"Google Suchergebnissen angezeigt werden können. Wenn Sie Produktbewertungen " +"aktiviert haben und dort im Expertenmodus bereits Rich Snippets aktiviert " +"haben, empfehlen wir die Ausgabe der Rich Snippets für Shopbewertungen nur " +"auf der Kategorieseite." + +#: includes/class-wc-trusted-shops-admin.php:394 +msgctxt "trusted-shops" +msgid "Activate rich snippets on" +msgstr "Rich Snippets aktivieren auf" + +#: includes/class-wc-trusted-shops-admin.php:395 +msgctxt "trusted-shops" +msgid "category pages" +msgstr "Kategorieseiten" + +#: includes/class-wc-trusted-shops-admin.php:403 +msgctxt "trusted-shops" +msgid "product pages" +msgstr "Produktdetailseiten" + +#: includes/class-wc-trusted-shops-admin.php:411 +msgctxt "trusted-shops" +msgid "homepage (not recommended)" +msgstr "Startseite (nicht empfohlen)" + +#: includes/class-wc-trusted-shops-admin.php:419 +msgctxt "trusted-shops" +msgid "Rich snippets code" +msgstr "Rich Snippets Code" + +#: includes/class-wc-trusted-shops-admin.php:431 +msgctxt "trusted-shops" +msgid "Configure your Product Reviews " +msgstr "Konfigurieren Sie die Produktbewertungen" + +#: includes/class-wc-trusted-shops-admin.php:432 +#, php-format +msgctxt "trusted-shops" +msgid "To use Product Reviews, activate them in your %s first." +msgstr "" +"Um Produktbewertungen nutzen zu können, schalten Sie diese zuerst in Ihrem " +"%s frei." + +#: includes/class-wc-trusted-shops-admin.php:432 +msgctxt "trusted-shops" +msgid "Trusted Shops package" +msgstr "Trusted Shops Paket" + +#: includes/class-wc-trusted-shops-admin.php:438 +msgctxt "trusted-shops" +msgid "Collect Product Reviews" +msgstr "Produktbewertungen sammeln" + +#: includes/class-wc-trusted-shops-admin.php:439 +msgctxt "trusted-shops" +msgid "" +"Show Product Reviews on the product page in a separate tab, just as shown on " +"the picture on the right." +msgstr "" +"Zeige Produktbewertungen auf der Produktseite in einem separaten Reiter, wie " +"in der Grafik rechts abgebildet." + +#: includes/class-wc-trusted-shops-admin.php:447 +msgctxt "trusted-shops" +msgid "Reviews" +msgstr "Bewertungen" + +#: includes/class-wc-trusted-shops-admin.php:448 +#: includes/class-wc-trusted-shops-admin.php:457 +msgctxt "trusted-shops" +msgid "You can choose a name for the tab with your Product Reviews." +msgstr "" +"Sie können selbst bestimmen, wie der Reiter in dem Ihre Produktbewertungen " +"angezeigt werden, heißen soll." + +#: includes/class-wc-trusted-shops-admin.php:449 +msgctxt "trusted-shops" +msgid "Show Product Reviews on the product detail page in an additional tab." +msgstr "Produktbewertungen auf der Produktseite in separatem Reiter anzeigen." + +#: includes/class-wc-trusted-shops-admin.php:456 +msgctxt "trusted-shops" +msgid "Name of Product Reviews tab" +msgstr "Bezeichnung Reiter" + +#: includes/class-wc-trusted-shops-admin.php:460 +msgctxt "trusted-shops" +msgid "Product reviews" +msgstr "Produktbewertungen" + +#: includes/class-wc-trusted-shops-admin.php:464 +msgctxt "trusted-shops" +msgid "Border color" +msgstr "Umrandung" + +#: includes/class-wc-trusted-shops-admin.php:465 +msgctxt "trusted-shops" +msgid "Set the color for the frame around your Product Reviews." +msgstr "Legen Sie die Farbe für den Rahmen um die Produktbewertungen fest." + +#: includes/class-wc-trusted-shops-admin.php:473 +msgctxt "trusted-shops" +msgid "Set the background color for your Product Reviews." +msgstr "Legen Sie die Hintergrundfarbe für die Produktbewertungen fest." + +#: includes/class-wc-trusted-shops-admin.php:480 +#: includes/class-wc-trusted-shops-admin.php:530 +msgctxt "trusted-shops" +msgid "Star color" +msgstr "Farbe der Sterne" + +#: includes/class-wc-trusted-shops-admin.php:481 +msgctxt "trusted-shops" +msgid "Set the color for the Product Review stars in your Product Reviews tab." +msgstr "" +"Legen Sie die Farbe der Sterne fest, die in Ihrem Produktbewertungs-Reiter " +"angezeigt werden." + +#: includes/class-wc-trusted-shops-admin.php:488 +#: includes/class-wc-trusted-shops-admin.php:538 +msgctxt "trusted-shops" +msgid "Star size" +msgstr "Größe der Sterne" + +#: includes/class-wc-trusted-shops-admin.php:493 +msgctxt "trusted-shops" +msgid "Set the size for the Product Review stars in your Product Reviews tab." +msgstr "" +"Legen Sie die Größe der Sterne fest, die in Ihrem Produktbewertungs-Reiter " +"angezeigt werden." + +#: includes/class-wc-trusted-shops-admin.php:504 +msgctxt "trusted-shops" +msgid "Product Sticker Code" +msgstr "Produktbewertungen Code" + +#: includes/class-wc-trusted-shops-admin.php:513 +#: includes/class-wc-trusted-shops-admin.php:579 +msgctxt "trusted-shops" +msgid "jQuerySelector" +msgstr "jQuerySelector" + +#: includes/class-wc-trusted-shops-admin.php:514 +msgctxt "trusted-shops" +msgid "" +"Please choose where your Product Reviews shall be displayed on the Product " +"detail page." +msgstr "" +"Wählen Sie, wo die Produktbewertungen auf der Produktdetailseite angezeigt " +"werden sollen." + +#: includes/class-wc-trusted-shops-admin.php:521 +msgctxt "trusted-shops" +msgid "Rating stars" +msgstr "Bewertungssterne" + +#: includes/class-wc-trusted-shops-admin.php:522 +msgctxt "trusted-shops" +msgid "Show star ratings on the product detail page below your product name." +msgstr "Bewertungssterne auf der Produktseite unter dem Produktnamen anzeigen." + +#: includes/class-wc-trusted-shops-admin.php:523 +msgctxt "trusted-shops" +msgid "" +"Display Product Review stars on product pages below the product name, just " +"as shown in the picture on the right." +msgstr "" +"Zeige Bewertungssterne auf der Produktseite unter dem Produktnamen, wie in " +"der Grafik rechts abgebildet." + +#: includes/class-wc-trusted-shops-admin.php:532 +msgctxt "trusted-shops" +msgid "" +"Set the color for the review stars, that are displayed on the product page, " +"below your product name." +msgstr "" +"Legen Sie die Farbe der Sterne fest, die auf der Produktseite unter dem " +"Produktnamen angezeigt werden." + +#: includes/class-wc-trusted-shops-admin.php:540 +msgctxt "trusted-shops" +msgid "" +"Set the size for the review stars that are displayed on the product page, " +"below your product name." +msgstr "" +"Legen Sie die Größe der Sterne fest, die auf der Produktseite unter dem " +"Produktnamen angezeigt werden." + +#: includes/class-wc-trusted-shops-admin.php:554 +msgctxt "trusted-shops" +msgid "Font size" +msgstr "Schriftgröße" + +#: includes/class-wc-trusted-shops-admin.php:556 +msgctxt "trusted-shops" +msgid "Set the font size for the text that goes with your review stars." +msgstr "Legen Sie die Schriftgröße für den Text zu den Bewertungssternen fest." + +#: includes/class-wc-trusted-shops-admin.php:570 +msgctxt "trusted-shops" +msgid "Product Review Code" +msgstr "Produktbewertungen Code" + +#: includes/class-wc-trusted-shops-admin.php:580 +msgctxt "trusted-shops" +msgid "" +"Please choose where your Product Review Stars shall be displayed on the " +"Product Detail page." +msgstr "" +"Wählen Sie, wo die Produktbewertungssterne auf der Produktdetailseite " +"angezeigt werden sollen." + +#: includes/class-wc-trusted-shops-admin.php:587 +msgctxt "trusted-shops" +msgid "Brand attribute" +msgstr "Marken-Produktattribut" + +#: includes/class-wc-trusted-shops-admin.php:588 +#, php-format +msgctxt "trusted-shops" +msgid "Create brand attribute %s" +msgstr "Marken-Produktattribut %s erstellen" + +#: includes/class-wc-trusted-shops-admin.php:589 +msgctxt "trusted-shops" +msgid "" +"Brand name of the product. By passing this information on to Google, you " +"improve your chances of having Google identify your products. Assign your " +"brand attribute. If your products don't have a GTIN, you can pass on the " +"brand name and the MPN to use Google Integration." +msgstr "" +"Markenname des Produkts. Durch Übergeben dieser Variable verbessern Sie die " +"Möglichkeit Ihre Produkte von Google eindeutig identifizieren zu lassen. " +"Weisen Sie ein Marken-Produktattribut zu. Wenn Ihre Produkte keine GTIN " +"haben, können Sie den Markennamen zusammen mit der MPN übergeben, um die " +"Google Integration zu nutzen." + +#: includes/class-wc-trusted-shops-admin.php:595 +msgctxt "trusted-shops" +msgid "None" +msgstr "Keine" + +#: includes/class-wc-trusted-shops-admin.php:606 +msgctxt "trusted-shops" +msgid "Configure your Review Requests" +msgstr "Konfigurieren Sie die Bewertungserinnerungen" + +#: includes/class-wc-trusted-shops-admin.php:607 +msgctxt "trusted-shops" +msgid "" +"7 days after an order has been placed, Trusted Shops automatically sends an " +"invite to your customers. If you want to set a different time for sending " +"automatic Review Requests, please activate the option below. If you want to " +"send review requests with legal certainty, you need your customers' consent " +"to receive Review Requests. You also have to include an option to " +"unsubscribe." +msgstr "" +"Trusted Shops versendet 7 Tage nach Bestellung automatisch eine " +"Bewertungserinnerung an Ihre Kunden. Wenn Sie lieber selbst entscheiden " +"möchten, wann Bewertungsanfragen versendet werden, aktivieren Sie die " +"untenstehende Option. Möchten Sie rechtssicher Bewertungs-Erinnerungen " +"verschicken, so benötigen Sie die ausdrückliche Einwilligung Ihrer Kunden " +"zum Empfang von Bewertungsemails. Sie müssen Ihren Kunden zudem eine " +"Möglichkeit geben, Bewertungserinnerungen wieder abzubestellen." + +#: includes/class-wc-trusted-shops-admin.php:613 +msgctxt "trusted-shops" +msgid "Enable Review Requests" +msgstr "Bewertungserinnerungen aktivieren" + +#: includes/class-wc-trusted-shops-admin.php:622 +msgctxt "trusted-shops" +msgid "WooCommerce status" +msgstr "Bestellstatus" + +#: includes/class-wc-trusted-shops-admin.php:623 +msgctxt "trusted-shops" +msgid "" +"We recommend choosing the order status that you set when your products have " +"been shipped." +msgstr "" +"Wählen Sie hier am besten den Bestellstatus aus WooCommerce aus, den Sie " +"einstellen, wenn Ihre Ware versendet wurde." + +#: includes/class-wc-trusted-shops-admin.php:631 +msgctxt "trusted-shops" +msgid "Days until Review Request" +msgstr "Tage bis zur Erinnerung" + +#: includes/class-wc-trusted-shops-admin.php:632 +msgctxt "trusted-shops" +msgid "" +"Set the number of days to wait after an order has reached the order status " +"you selected above before having a review request sent to your customers." +msgstr "" +"Stellen Sie hier ein nach wie vielen Tagen nach Erreichen des oben " +"ausgewählten Bestellstatus die Bewertungserinnerung an den Käufer versendet " +"werden soll." + +#: includes/class-wc-trusted-shops-admin.php:644 +msgctxt "trusted-shops" +msgid "Permission via checkbox" +msgstr "Einwilligung per Checkbox" + +#: includes/class-wc-trusted-shops-admin.php:645 +msgctxt "trusted-shops" +msgid "" +"If the checkbox is activated, only customers who gave their consent will " +"receive Review Requests." +msgstr "" +"Bei aktivierter Checkbox erhalten nur die Kunden eine Bewertungserinnerung, " +"die ihr Einverständnis gegeben haben." + +#: includes/class-wc-trusted-shops-admin.php:649 +msgctxt "trusted-shops" +msgid "Edit checkbox" +msgstr "Checkbox anpassen" + +#: includes/class-wc-trusted-shops-admin.php:653 +msgctxt "trusted-shops" +msgid "Unsubscribe via link" +msgstr "Abmeldung per Link" + +#: includes/class-wc-trusted-shops-admin.php:654 +msgctxt "trusted-shops" +msgid "Allows the customer to unsubscribe from Review Requests." +msgstr "" +"Erlaubt es dem Kunden sich von Bewertungserinnerungen per Link abzumelden." + +#: includes/class-wc-trusted-shops-admin.php:755 +msgctxt "trusted-shops" +msgid "How does Trusted Shops make your shop better?" +msgstr "Wie macht Trusted Shops Ihren Shop besser?" + +#: includes/class-wc-trusted-shops-admin.php:757 +msgctxt "trusted-shops" +msgid "Get your account" +msgstr "Erstellen Sie Ihren Account" + +#: includes/class-wc-trusted-shops-admin.php:777 +msgctxt "trusted-shops" +msgid "Product Reviews on the product detail page in an additional tab" +msgstr "Produktbewertungen auf der Produktseite in einem separatem Reiter" + +#: includes/class-wc-trusted-shops-admin.php:780 +msgctxt "trusted-shops" +msgid "Show Star-Ratings on the product detail page below your product name" +msgstr "Bewertungssterne unter dem Produktnamen auf der Produktseite" + +#: includes/class-wc-trusted-shops-admin.php:784 +msgctxt "trusted-shops" +msgid "" +"Please note: If you want to send review requests through WooCommerce, you " +"should deactivate automated review requests through Trusted Shops. To do so, " +"please go to your My Trusted Shops account. Log in and go to Reviews > " +"Settings and deactivate \"Collect reviews automatically\"" +msgstr "" +"Bitte beachten Sie: Wenn Sie Bewertungserinnerungen über WooCommerce " +"versenden möchtest, sollten Sie den Versand von automatischen " +"Bewertungserinnerungen über Trusted Shops deaktivieren. Gehen Sie dazu in " +"Ihren My Trusted Shops Account. Loggen Sie sich ein und gehen Sie zu " +"Bewertungen > Konfiguration und deaktivieren Sie dort „Bewertungen " +"automatisch sammeln“." + +#: includes/class-wc-trusted-shops-admin.php:785 +msgctxt "trusted-shops" +msgid "To your My Trusted Shops account" +msgstr "Zu Ihrem My Trusted Shops Account" + +#: includes/class-wc-trusted-shops-admin.php:789 +msgctxt "trusted-shops" +msgid "" +"Export your customer information here and upload it in the Trusted Shops " +"Review Collector. To do so go to your My Trusted Shops account. Log in and " +"go to Reviews > Shop Reviews > Review Collector" +msgstr "" +"Exportieren Sie hier die Kundendaten und laden Sie diese im Trusted Shops " +"Review Collector hoch. Gehen Sie dazu in Ihren My Trusted Shops Account. " +"Loggen Sie sich ein und gehen Sie zu Bewertungen > Shopbewertungen > Review " +"Collector" + +#: includes/class-wc-trusted-shops-admin.php:790 +msgctxt "trusted-shops" +msgid "To the Trusted Shops Review Collector" +msgstr "Zum Trusted Shops Review Collector" + +#: includes/class-wc-trusted-shops-admin.php:880 +msgctxt "trusted-shops" +msgid "Review Collector" +msgstr "Review Collector" + +#: includes/class-wc-trusted-shops-admin.php:882 +#, php-format +msgctxt "trusted-shops" +msgid "" +"Want to collect reviews for orders that were placed before your Trusted " +"Shops Integration? No problem. Export old orders here and upload them in " +"your %s." +msgstr "" +"Sie möchten nachträglich Bewertungen zu Bestellungen sammeln, die vor der " +"Trusted Shops Integration getätigt wurden? Kein Problem. Exportieren Sie " +"alte Bestellungen hier und laden Sie diese in Ihrem %s hoch." + +#: includes/class-wc-trusted-shops-admin.php:882 +msgctxt "trusted-shops" +msgid "My Trusted Shops account" +msgstr "My Trusted Shops Account" + +#: includes/class-wc-trusted-shops-admin.php:888 +msgctxt "trusted-shops" +msgid "Export orders" +msgstr "Bestellungen exportieren" + +#: includes/class-wc-trusted-shops-admin.php:888 +msgctxt "trusted-shops" +msgid "" +"Export your customer and order information of the last x days and upload " +"them in your My Trusted Shops Account." +msgstr "" +"Exportieren Sie Ihre Kunden- und Bestelldaten der letzten x Tage und laden " +"Sie diese in Ihrem My Trusted Shops Account hoch." + +#: includes/class-wc-trusted-shops-admin.php:892 +msgctxt "trusted-shops" +msgid "30 days" +msgstr "30 Tage" + +#: includes/class-wc-trusted-shops-admin.php:893 +msgctxt "trusted-shops" +msgid "60 days" +msgstr "60 Tage" + +#: includes/class-wc-trusted-shops-admin.php:894 +msgctxt "trusted-shops" +msgid "90 days" +msgstr "90 Tage" + +#: includes/class-wc-trusted-shops-admin.php:896 +#, php-format +msgctxt "trusted-shops" +msgid "Upload customer and order information %s." +msgstr "Kunden- und Bestelldaten %s hochladen" + +#: includes/class-wc-trusted-shops-admin.php:899 +msgctxt "trusted-shops" +msgid "Days until reminder mail" +msgstr "Tage bis zur Erinnerung" + +#: includes/class-wc-trusted-shops-admin.php:899 +msgctxt "trusted-shops" +msgid "" +"Set the number of days to wait after the order date before having a Review " +"Request sent to your customers." +msgstr "" +"Stellen Sie hier ein, wie viele Tage zwischen der Bestellung und dem Versand " +"der Bewertungserinnerung liegen soll." + +#: includes/class-wc-trusted-shops-admin.php:903 +msgctxt "trusted-shops" +msgid "Start export" +msgstr "Export starten" + +#: includes/class-wc-trusted-shops-core.php:55 +#: includes/class-wc-trusted-shops-core.php:64 +#: includes/class-wc-ts-dependencies.php:36 +#: includes/class-wc-ts-dependencies.php:45 +msgctxt "trusted-shops" +msgid "Cheatin’ huh?" +msgstr "So geht das leider nicht.." + +#: includes/class-wc-trusted-shops-core.php:210 +msgctxt "trusted-shops" +msgid "Yes" +msgstr "Ja" + +#: includes/class-wc-trusted-shops-core.php:210 +msgctxt "trusted-shops" +msgid "No" +msgstr "Nein" + +#: includes/class-wc-trusted-shops-core.php:258 +#, php-format +msgctxt "trusted-shops" +msgid "" +"If the App helped you, please leave a %s★★" +"★★★%s in the Wordpress plugin repository." +msgstr "" +"Wenn Ihnen die App hilft, hinterlassen Sie bitte eine " +"%s★★★★★%s Bewertung in der WordPress Plugin " +"Bibliothek." + +#: includes/class-wc-trusted-shops-core.php:407 +msgctxt "trusted-shops" +msgid "Settings" +msgstr "Einstellungen" + +#: includes/class-wc-trusted-shops-review-exporter.php:64 +msgctxt "trusted-shops" +msgid "Order ID" +msgstr "Bestellnummer" + +#: includes/class-wc-trusted-shops-review-exporter.php:65 +msgctxt "trusted-shops" +msgid "Order date" +msgstr "Bestelldatum" + +#: includes/class-wc-trusted-shops-review-exporter.php:66 +msgctxt "trusted-shops" +msgid "# Days" +msgstr "# Tage" + +#: includes/class-wc-trusted-shops-review-exporter.php:67 +msgctxt "trusted-shops" +msgid "Email" +msgstr "E-Mail" + +#: includes/class-wc-trusted-shops-review-exporter.php:68 +msgctxt "trusted-shops" +msgid "First name" +msgstr "Vorname" + +#: includes/class-wc-trusted-shops-review-exporter.php:69 +msgctxt "trusted-shops" +msgid "Last name" +msgstr "Nachname" + +#: includes/class-wc-trusted-shops-template-hooks.php:121 +#, php-format +msgctxt "trusted-shops" +msgid "" +"Your review reminder e-mail has been cancelled successfully. Return to %s." +msgstr "" +"Ihre Bewertungserinnerung wurde erfolgreich deaktiviert. Kehren Sie zurück " +"zur %s." + +#: includes/class-wc-trusted-shops-template-hooks.php:121 +msgctxt "trusted-shops" +msgid "Home" +msgstr "Startseite" + +#: includes/class-wc-trusted-shops-template-hooks.php:193 +msgctxt "trusted-shops" +msgid "" +"Yes, I would like to be reminded via e-mail after {days} day(s) to review my " +"order. I am able to cancel the reminder at any time by clicking on the " +"\"cancel review reminder\" link within the order confirmation." +msgstr "" +"Ja, ich bin damit einverstanden, eine Erinnerung per E-Mail zur Bewertung " +"nach {days} Tage(n) zu erhalten. Ich kann mich jederzeit davon abmelden bzw. " +"widersprechen, indem ich dem Link „von der Bewertungserinnerung abmelden“ in " +"der Bestellbestätigung folge." + +#: includes/class-wc-trusted-shops-template-hooks.php:198 +msgctxt "trusted-shops" +msgid "Please allow us to send a review reminder by e-mail." +msgstr "" +"Bitte akzeptieren Sie den Erhalt einer Bewertungserinnerung per E-Mail." + +#: includes/class-wc-trusted-shops-template-hooks.php:201 +msgctxt "trusted-shops" +msgid "Review reminder" +msgstr "Bewertungs Erinnerung" + +#: includes/class-wc-trusted-shops-template-hooks.php:202 +msgctxt "trusted-shops" +msgid "Asks the customer to receive a Trusted Shops review reminder." +msgstr "" +"Holt die Erlaubnis zum Senden einer einmaligen Trusted Shops " +"Bewertungserinnerung ein." + +#: includes/emails/class-wc-ts-email-customer-trusted-shops.php:24 +msgctxt "trusted-shops" +msgid "Trusted Shops Review Reminder" +msgstr "Trusted Shops Bewertungs-Erinnerung" + +#: includes/emails/class-wc-ts-email-customer-trusted-shops.php:25 +msgctxt "trusted-shops" +msgid "" +"This E-Mail is being sent to a customer to remind him about the possibility " +"to leave a review at Trusted Shops." +msgstr "" +"Diese E-Mail wird einmalig an Kunden verschickt, um diese an die Abgabe " +"einer Bewertung bei Trusted Shops zu erinnern." + +#: includes/emails/class-wc-ts-email-customer-trusted-shops.php:54 +msgctxt "trusted-shops" +msgid "Please rate your {site_title} order from {order_date}" +msgstr "Bitte bewerten Sie Ihren Einkauf vom {order_date} bei {site_title}" + +#: includes/emails/class-wc-ts-email-customer-trusted-shops.php:64 +msgctxt "trusted-shops" +msgid "Please rate your Order" +msgstr "Bitte bewerten Sie Ihren Einkauf" + +#: includes/widgets/class-wc-trusted-shops-widget-review-sticker.php:19 +msgctxt "trusted-shops" +msgid "Show your TS shop review sticker." +msgstr "Zeige den Trusted Shops Review Sticker an." + +#: includes/widgets/class-wc-trusted-shops-widget-review-sticker.php:21 +msgctxt "trusted-shops" +msgid "Trusted Shops Shop Review Sticker" +msgstr "Trusted Shops Shop Review Sticker" + +#: includes/widgets/class-wc-trusted-shops-widget-review-sticker.php:25 +#: includes/widgets/class-wc-trusted-shops-widget-review-sticker.php:46 +msgctxt "trusted-shops" +msgid "Trusted Shops Reviews" +msgstr "Trusted Shops Bewertung" + +#: includes/widgets/class-wc-trusted-shops-widget-review-sticker.php:26 +msgctxt "trusted-shops" +msgid "Title" +msgstr "Bezeichnung" + +#: src/Package.php:53 +msgctxt "trusted-shops" +msgid "" +"Trustbadge Reviews for WooCommerce needs at least WooCommerce version 3.1 to " +"run." +msgstr "" +"Trustbadge Reviews for WooCommerce benötigt mind. WooCommerce Version 3.1 um " +"zu starten." + +#: templates/emails/customer-trusted-shops.php:18 +#: templates/emails/plain/customer-trusted-shops.php:12 +#, php-format +msgctxt "trusted-shops" +msgid "Dear %s %s," +msgstr "Sehr geehrte(r) %s %s," + +#: templates/emails/customer-trusted-shops.php:19 +#: templates/emails/plain/customer-trusted-shops.php:14 +#, php-format +msgctxt "trusted-shops" +msgid "" +"You have recently shopped at %s. Thank you! We would be glad if you spent " +"some time to write a review about your order. To do so please follow follow " +"the link." +msgstr "" +"Sie haben vor einiger Zeit bei %s eingekauft. Vielen Dank! Wir wären froh " +"darüber, wenn Sie sich die Zeit nehmen und Ihren Einkauf bewerten würden. Um " +"dies nun zu tun, klicken Sie bitte auf den nachfolgenden Link." + +#: templates/emails/customer-trusted-shops.php:22 +msgctxt "trusted-shops" +msgid "Rate Order now" +msgstr "Einkauf jetzt bewerten" + +#~ msgctxt "trusted-shops" +#~ msgid "Duplicate Plugin installation" +#~ msgstr "Doppelte Plugin Installation" + +#, php-format +#~ msgctxt "trusted-shops" +#~ msgid "" +#~ "It seems like you've installed WooCommerce Germanized and Trustbadge " +#~ "Reviews for WooCommerce. Please deactivate Trustbadge Reviews for " +#~ "WooCommerce as long as you are using WooCommerce Germanized. You can " +#~ "manage your Trusted Shops configuration within your %s." +#~ msgstr "" +#~ "Es scheint als hättest du WooCommerce Germanized und Trustbadge Reviews " +#~ "for WooCommerce installiert. Bitte deaktiviere das Trustbadge Reviews " +#~ "Plugin solange du WooCommerce Germanized verwendest. Du kannst deine " +#~ "Trusted Shops Konfiguration in deinen %s verwalten." + +#~ msgctxt "trusted-shops" +#~ msgid "Germanized settings" +#~ msgstr "Germanized Einstellungen" + +#~ msgctxt "trusted-shops" +#~ msgid "Deactivate standalone version" +#~ msgstr "Deaktiviere die Standalone-Version" + +#~ msgctxt "trusted-shops" +#~ msgid "(WooCommerce Product Reviews will be replaced)" +#~ msgstr "(WooCommerce Produktbewertungen werden ersetzt)" + +#, php-format +#~ msgid "" +#~ "Please install WooCommerce before " +#~ "installing WooCommerce Germanized. Thank you!" +#~ msgstr "" +#~ "Bitte installiere WooCommerce bevor " +#~ "du WooCommerce Germanized installierst. Vielen Dank!" diff --git a/packages/woocommerce-trusted-shops/i18n/languages/woocommerce-trusted-shops-fr_FR.mo b/packages/woocommerce-trusted-shops/i18n/languages/woocommerce-trusted-shops-fr_FR.mo new file mode 100644 index 0000000000000000000000000000000000000000..19ef22d77028571be02084888df4211d8741df94 GIT binary patch literal 26951 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 IO=s}`08ueZ82|tP literal 0 HcmV?d00001 diff --git a/packages/woocommerce-trusted-shops/i18n/languages/woocommerce-trusted-shops-fr_FR.po b/packages/woocommerce-trusted-shops/i18n/languages/woocommerce-trusted-shops-fr_FR.po new file mode 100644 index 000000000..7e00b75f8 --- /dev/null +++ b/packages/woocommerce-trusted-shops/i18n/languages/woocommerce-trusted-shops-fr_FR.po @@ -0,0 +1,1165 @@ +msgid "" +msgstr "" +"Project-Id-Version: WooCommerce Trusted Shops\n" +"POT-Creation-Date: 2019-01-14 15:41+0100\n" +"PO-Revision-Date: 2019-02-18 15:10+0100\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 2.2.1\n" +"X-Poedit-Basepath: ../..\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Poedit-KeywordsList: __;_e;__ngettext:1,2;_n:1,2;__ngettext_noop:1,2;" +"_n_noop:1,2;_c,_nc:4c,1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;_nx_noop:4c,1,2;" +"esc_attr_e;esc_html_e;esc_html__\n" +"X-Poedit-SearchPath-0: .\n" +"X-Poedit-SearchPathExcluded-0: node_modules\n" + +#: includes/admin/views/html-duplicate-plugin-notice.php:19 +msgctxt "trusted-shops" +msgid "Duplicate Plugin installation" +msgstr "Plugins installés en double" + +#: includes/admin/views/html-duplicate-plugin-notice.php:21 +#, php-format +msgctxt "trusted-shops" +msgid "" +"It seems like you've installed WooCommerce Germanized and Trustbadge Reviews " +"for WooCommerce. Please deactivate Trustbadge Reviews for WooCommerce as " +"long as you are using WooCommerce Germanized. You can manage your Trusted " +"Shops configuration within your %s." +msgstr "" +"Il semblerait que vous ayez installé WooCommerce Germanized et Trustbadge " +"Reviews for WooCommerce. Veuillez s’il vous plait désactiver Trustbadge " +"Reviews for WooCommerce tant que vous utilisez WooCommerce Germanized. Vous " +"pouvez modifier votre configuration Trusted Shops au sein de vos %s." + +#: includes/admin/views/html-duplicate-plugin-notice.php:21 +msgctxt "trusted-shops" +msgid "Germanized settings" +msgstr "Germanized paramètres" + +#: includes/admin/views/html-duplicate-plugin-notice.php:23 +msgctxt "trusted-shops" +msgid "Deactivate standalone version" +msgstr "Désactivez la version standalone" + +#: includes/admin/views/html-notice-dependencies.php:16 +msgctxt "trusted-shops" +msgid "Dependencies Missing or Outdated" +msgstr "Composants manquantes ou obsolètes" + +#: includes/admin/views/html-notice-dependencies.php:24 +msgctxt "trusted-shops" +msgid "" +"To use WooCommerce Trusted Shops you may at first install the following " +"plugins:" +msgstr "" +"Pour utiliser Trusted Shops for WooCommerce, il vous faut d’abord installer " +"les plugins suivants :" + +#: includes/admin/views/html-notice-dependencies.php:28 +#, php-format +msgctxt "trusted-shops" +msgid "Install %s" +msgstr "Installer %s" + +#: includes/admin/views/html-notice-dependencies.php:36 +msgctxt "trusted-shops" +msgid "" +"To use WooCommerce Trusted Shops you may at first update the following " +"plugins to a newer version:" +msgstr "" +"Pour utiliser Trusted Shops for WooCommerce, vous devez d’abord actualiser " +"les plugins suivants et installer une version plus récente:" + +#: includes/admin/views/html-notice-dependencies.php:40 +#, php-format +msgctxt "trusted-shops" +msgid "%s required in at least version %s" +msgstr "%s requiert la version %s ou supérieure" + +#: includes/admin/views/html-notice-dependencies.php:49 +msgctxt "trusted-shops" +msgid "Check for Updates" +msgstr "Rechercher de mises à jour" + +#: includes/admin/views/html-notice-dependencies.php:50 +msgctxt "trusted-shops" +msgid "or" +msgstr "ou" + +#: includes/admin/views/html-notice-dependencies.php:51 +msgctxt "trusted-shops" +msgid "Install an older version" +msgstr "Installer une version antérieure" + +#: includes/admin/views/html-notice-update.php:12 +msgctxt "trusted-shops" +msgid "" +"WooCommerce Trusted Shops Data Update Required – We " +"just need to update your install to the latest version" +msgstr "" +"Mise à jour de la base de données Trusted Shops WooCommerce requise – Nous devons mettre à jour votre installation vers la version " +"la plus récente." + +#: includes/admin/views/html-notice-update.php:13 +msgctxt "trusted-shops" +msgid "Run the updater" +msgstr "Démarrer l’actualisation" + +#: includes/admin/views/html-notice-update.php:17 +msgctxt "trusted-shops" +msgid "" +"It is strongly recommended that you backup your database before proceeding. " +"Are you sure you wish to run the updater now?" +msgstr "" +"Nous vous recommandons fortement de sauvegarder votre base de données avant " +"de procéder à la mise à jour. Êtes-vous sûr de vouloir effectuer la mise à " +"jour maintenant?" + +#: includes/admin/views/html-wpml-notice.php:11 +msgctxt "trusted-shops" +msgid "WPML Support" +msgstr "Prise en charge WPML" + +#: includes/admin/views/html-wpml-notice.php:14 +msgctxt "trusted-shops" +msgid "" +"These settings serve as default settings for all your languages. To adjust " +"the settings for a certain language, please switch your admin language " +"through the WPML language switcher and adjust the corresponding settings." +msgstr "" +"Ces paramètres sont les paramètres par défaut pour toutes vos langues. Afin " +"d’ajuster ces paramètres à une certaine langue, il vous faut changer votre " +"langue système à l’aide du plug-in multilingue WPML et adapter les " +"paramètres correspondants." + +#: includes/admin/views/html-wpml-notice.php:16 +#, php-format +msgctxt "trusted-shops" +msgid "" +"These settings apply for your %s shop. To adjust settings for another " +"language, please switch your admin language through the WPML language " +"switcher." +msgstr "" +"Ces paramètres s’appliquent pour votre boutique %s. Pour adapter les " +"paramètres à une autre langue, veuillez changer votre langue système à " +"l’aide du plug-in multilingue WPML." + +#: includes/class-wc-trusted-shops-admin.php:90 +#: includes/class-wc-trusted-shops-admin.php:127 +msgctxt "trusted-shops" +msgid "GTIN" +msgstr "GTIN" + +#: includes/class-wc-trusted-shops-admin.php:90 +#: includes/class-wc-trusted-shops-admin.php:127 +msgctxt "trusted-shops" +msgid "" +"ID that allows your products to be identified worldwide. If you want to " +"display your Trusted Shops Product Reviews in Google Shopping and paid " +"Google adverts, Google needs the GTIN." +msgstr "" +"Le GTIN est le numéro d’identification qui permet d’identifier sans " +"équivoque les produits dans le monde entier. Google a besoin de l’attribut " +"GTIN pour afficher vos avis produits dans Google Shopping et dans les " +"annonces payantes Google." + +#: includes/class-wc-trusted-shops-admin.php:94 +#: includes/class-wc-trusted-shops-admin.php:128 +msgctxt "trusted-shops" +msgid "MPN" +msgstr "MPN" + +#: includes/class-wc-trusted-shops-admin.php:94 +#: includes/class-wc-trusted-shops-admin.php:128 +msgctxt "trusted-shops" +msgid "" +"If you don't have a GTIN for your products, you can pass the brand name and " +"the MPN on to Google to use the Trusted Shops Google Integration." +msgstr "" +"Si vos produits n’ont pas de GTIN, vous pouvez indiquer le nom de la marque " +"ainsi que le MPN pour utiliser l’intégration Google." + +#: includes/class-wc-trusted-shops-admin.php:152 +msgctxt "trusted-shops" +msgid "Brand" +msgstr "Marque" + +#: includes/class-wc-trusted-shops-admin.php:192 +msgctxt "trusted-shops" +msgid "This field is mandatory" +msgstr "Ce champ est obligatoire" + +#: includes/class-wc-trusted-shops-admin.php:199 +msgctxt "trusted-shops" +msgid "Trusted Shops Options" +msgstr "Options Trusted Shops" + +#: includes/class-wc-trusted-shops-admin.php:206 +msgctxt "trusted-shops" +msgid "Arial" +msgstr "Arial" + +#: includes/class-wc-trusted-shops-admin.php:207 +msgctxt "trusted-shops" +msgid "Geneva" +msgstr "Geneva" + +#: includes/class-wc-trusted-shops-admin.php:208 +msgctxt "trusted-shops" +msgid "Georgia" +msgstr "Georgia" + +#: includes/class-wc-trusted-shops-admin.php:209 +msgctxt "trusted-shops" +msgid "Helvetica" +msgstr "Helvetica" + +#: includes/class-wc-trusted-shops-admin.php:210 +msgctxt "trusted-shops" +msgid "Sans-serif" +msgstr "Sans-serif" + +#: includes/class-wc-trusted-shops-admin.php:211 +msgctxt "trusted-shops" +msgid "Serif" +msgstr "Serif" + +#: includes/class-wc-trusted-shops-admin.php:212 +msgctxt "trusted-shops" +msgid "Trebuchet MS" +msgstr "Trebuchet MS" + +#: includes/class-wc-trusted-shops-admin.php:213 +msgctxt "trusted-shops" +msgid "Verdana" +msgstr "Verdana" + +#: includes/class-wc-trusted-shops-admin.php:236 +msgctxt "trusted-shops" +msgid "Trusted Shops Integration" +msgstr "Intégration Trusted Shops" + +#: includes/class-wc-trusted-shops-admin.php:237 +#, php-format +msgctxt "trusted-shops" +msgid "Do you need help with integrating your Trustbadge? %s" +msgstr "Avez-vous besoin d’aide pour intégrer le Trustbadge? %s" + +#: includes/class-wc-trusted-shops-admin.php:237 +msgctxt "trusted-shops" +msgid "To the step-by-step instructions" +msgstr "Accéder au guide" + +#: includes/class-wc-trusted-shops-admin.php:243 +msgctxt "trusted-shops" +msgid "Trusted Shops ID" +msgstr "Identifiants Trusted Shops" + +#: includes/class-wc-trusted-shops-admin.php:244 +msgctxt "trusted-shops" +msgid "" +"The Trusted Shops ID is a unique identifier for your shop. You can find your " +"Trusted Shops ID in your My Trusted Shops account." +msgstr "" +"Les identifiants Trusted Shops servent à identifier votre boutique en ligne " +"sur Trusted Shops. Vous trouverez vos identifiants Trusted Shops (TSID) dans " +"votre compte My Trusted Shops." + +#: includes/class-wc-trusted-shops-admin.php:253 +msgctxt "trusted-shops" +msgid "Edit Mode" +msgstr "Mode édition" + +#: includes/class-wc-trusted-shops-admin.php:255 +#: includes/class-wc-trusted-shops-admin.php:316 +#: includes/class-wc-trusted-shops-admin.php:439 +msgctxt "trusted-shops" +msgid "" +"The advanced configuration is for users with programming skills. Here you " +"can create even more individual settings." +msgstr "" +"Le mode expert est conçu pour des utilisateurs ayant de bonnes connaissances " +"en programmation. Cliquer ici, pour avoir accès à des réglages personnalisés." + +#: includes/class-wc-trusted-shops-admin.php:259 +msgctxt "trusted-shops" +msgid "Standard configuration" +msgstr "Mode standard" + +#: includes/class-wc-trusted-shops-admin.php:260 +msgctxt "trusted-shops" +msgid "Advanced configuration" +msgstr "Mode expert" + +#: includes/class-wc-trusted-shops-admin.php:268 +msgctxt "trusted-shops" +msgid "Configure your Trustbadge" +msgstr "Configurer le Trustbadge" + +#: includes/class-wc-trusted-shops-admin.php:274 +msgctxt "trusted-shops" +msgid "Display Trustbadge" +msgstr "Afficher le Trustbadge" + +#: includes/class-wc-trusted-shops-admin.php:276 +msgctxt "trusted-shops" +msgid "Display the Trustbadge on all the pages of your shop." +msgstr "" +"Afficher le Trustbadge sur toutes les pages de votre boutique en ligne." + +#: includes/class-wc-trusted-shops-admin.php:283 +msgctxt "trusted-shops" +msgid "Variant" +msgstr "Variante" + +#: includes/class-wc-trusted-shops-admin.php:285 +msgctxt "trusted-shops" +msgid "You can display your Trustbadge with or without Review Stars." +msgstr "" +"Vous pouvez afficher le Trustbadge avec ou sans les étoiles d’évaluation." + +#: includes/class-wc-trusted-shops-admin.php:289 +#: includes/class-wc-trusted-shops-admin.php:780 +msgctxt "trusted-shops" +msgid "Display Trustbadge with review stars" +msgstr "Afficher le Trustbadge avec les étoiles d’évaluation" + +#: includes/class-wc-trusted-shops-admin.php:290 +#: includes/class-wc-trusted-shops-admin.php:784 +msgctxt "trusted-shops" +msgid "Display Trustbadge without review stars" +msgstr "Afficher le Trustbadge sans les étoiles d’évaluation" + +#: includes/class-wc-trusted-shops-admin.php:296 +msgctxt "trusted-shops" +msgid "Vertical Offset" +msgstr "Décalage vertical" + +#: includes/class-wc-trusted-shops-admin.php:297 +msgctxt "trusted-shops" +msgid "" +"Choose the distance that the Trustbadge will appear from the bottom-right " +"corner of the screen." +msgstr "" +"Choisissez l’espacement du Trustbadge® par rapport au bord inferieur droit " +"de l’écran." + +#: includes/class-wc-trusted-shops-admin.php:300 +#: includes/class-wc-trusted-shops-admin.php:509 +#: includes/class-wc-trusted-shops-admin.php:560 +#: includes/class-wc-trusted-shops-admin.php:575 +msgid "px" +msgstr "px" + +#: includes/class-wc-trusted-shops-admin.php:306 +#: includes/class-wc-trusted-shops-admin.php:516 +#: includes/class-wc-trusted-shops-admin.php:566 +#: includes/class-wc-trusted-shops-admin.php:582 +#, php-format +msgctxt "trusted-shops" +msgid "Please choose a non-negative number (at least %d)" +msgstr "Veuillez choisir un nombre positif (> %d)" + +#: includes/class-wc-trusted-shops-admin.php:312 +msgctxt "trusted-shops" +msgid "Trustbadge code" +msgstr "Trustbadge code" + +#: includes/class-wc-trusted-shops-admin.php:324 +msgctxt "trusted-shops" +msgid "Configure your Shop Reviews" +msgstr "Configurer les avis site" + +#: includes/class-wc-trusted-shops-admin.php:330 +msgctxt "trusted-shops" +msgid "Display Shop Review Sticker" +msgstr "Afficher la vignette avis site" + +#: includes/class-wc-trusted-shops-admin.php:331 +msgctxt "trusted-shops" +msgid "" +"To display the Shop Review Sticker, you have to assign the widget \"Trusted " +"Shops Review Sticker\"." +msgstr "" +"Pour afficher la vignette avis site, veuillez sélectionner le widget " +"« Vignette avis site Trusted Shops »." + +#: includes/class-wc-trusted-shops-admin.php:332 +#, php-format +msgctxt "trusted-shops" +msgid "Assign widget %s" +msgstr "Assigner le widget %s" + +#: includes/class-wc-trusted-shops-admin.php:332 +#: includes/class-wc-trusted-shops-admin.php:605 +#: includes/class-wc-trusted-shops-admin.php:905 +msgctxt "trusted-shops" +msgid "here" +msgstr "ici" + +#: includes/class-wc-trusted-shops-admin.php:340 +#: includes/class-wc-trusted-shops-admin.php:489 +msgctxt "trusted-shops" +msgid "Background color" +msgstr "Couleur de l’arrière-plan" + +#: includes/class-wc-trusted-shops-admin.php:341 +msgctxt "trusted-shops" +msgid "Choose the background color for your Review Sticker." +msgstr "Choisir la couleur de l’arrière-plan de la vignette d’avis." + +#: includes/class-wc-trusted-shops-admin.php:348 +msgctxt "trusted-shops" +msgid "Font" +msgstr "Police" + +#: includes/class-wc-trusted-shops-admin.php:350 +msgctxt "trusted-shops" +msgid "Choose the font for your Review Sticker." +msgstr "Choisir la police de la vignette d’avis." + +#: includes/class-wc-trusted-shops-admin.php:357 +msgctxt "trusted-shops" +msgid "Number of reviews displayed" +msgstr "Nombre d’avis" + +#: includes/class-wc-trusted-shops-admin.php:358 +msgctxt "trusted-shops" +msgid "" +"Display x alternating Shop Reviews in your Shop Review Sticker. You can " +"display between 1 and 5 alternating Shop Reviews." +msgstr "" +"Afficher x avis site en alternance sur votre vignette avis site. Vous pouvez " +"afficher en alternance de 1 à 5 avis." + +#: includes/class-wc-trusted-shops-admin.php:361 +msgctxt "trusted-shops" +msgid "Show x alternating reviews" +msgstr "Afficher x avis en alternance" + +#: includes/class-wc-trusted-shops-admin.php:368 +#: includes/class-wc-trusted-shops-admin.php:385 +#, php-format +msgctxt "trusted-shops" +msgid "Please choose a non-negative number between %d and %d" +msgstr "Veuillez choisir un nombre positif entre %d et %d" + +#: includes/class-wc-trusted-shops-admin.php:374 +msgctxt "trusted-shops" +msgid "Minimum rating displayed" +msgstr "Note minimale affichée" + +#: includes/class-wc-trusted-shops-admin.php:375 +msgctxt "trusted-shops" +msgid "Only show Shop Reviews with a minimum rating of x stars. " +msgstr "N’afficher que les avis site avec x étoiles ou plus. " + +#: includes/class-wc-trusted-shops-admin.php:378 +msgctxt "trusted-shops" +msgid "Star(s)" +msgstr "étoile(s)" + +#: includes/class-wc-trusted-shops-admin.php:391 +msgctxt "trusted-shops" +msgid "Sticker code" +msgstr "Code des vignettes avis clients" + +#: includes/class-wc-trusted-shops-admin.php:395 +#: includes/class-wc-trusted-shops-admin.php:523 +#: includes/class-wc-trusted-shops-admin.php:588 +msgctxt "trusted-shops" +msgid "" +"The advanced configuration is for users with programming skills. Here you " +"can perform even more individual settings." +msgstr "" +"Le mode expert est conçu pour des utilisateurs ayant de bonnes connaissances " +"en programmation. Cliquer ici, pour avoir accès à des réglages personnalisés." + +#: includes/class-wc-trusted-shops-admin.php:401 +msgctxt "trusted-shops" +msgid "Google Organic Search" +msgstr "Résultats de recherche organiques" + +#: includes/class-wc-trusted-shops-admin.php:402 +msgctxt "trusted-shops" +msgid "" +"Activate this option to give Google the opportunity to show your Shop " +"Reviews in Google organic search results." +msgstr "" +"Veuillez activer cette fonctionnalité pour permettre à Google d’afficher vos " +"avis site dans les résultats de recherche organiques." + +#: includes/class-wc-trusted-shops-admin.php:403 +msgctxt "trusted-shops" +msgid "" +"By activating this option, rich snippets will be integrated in the selected " +"pages so your shop review stars may be displayed in Google organic search " +"results. If you use Product Reviews and already activated rich snippets in " +"expert mode, we recommend integrating rich snippets for Shop Reviews on " +"category pages only." +msgstr "" +"En activant cette option, les rich snippets seront intégrés dans les pages " +"sélectionnées, de façon à ce que vos étoiles d’évaluation puissent être " +"affichées dans les résultats de recherche organiques de Google. Si vous avez " +"activé les avis produits et vous avez déjà activé les rich snippets dans le " +"mode expert, nous vous conseillons de n’activer les rich snippets pour les " +"avis site que sur la page de catégorie." + +#: includes/class-wc-trusted-shops-admin.php:410 +msgctxt "trusted-shops" +msgid "Activate rich snippets on" +msgstr "Activer les rich snippets sur" + +#: includes/class-wc-trusted-shops-admin.php:411 +msgctxt "trusted-shops" +msgid "category pages" +msgstr "les pages de catégories" + +#: includes/class-wc-trusted-shops-admin.php:419 +msgctxt "trusted-shops" +msgid "product pages" +msgstr "les pages produit" + +#: includes/class-wc-trusted-shops-admin.php:427 +msgctxt "trusted-shops" +msgid "homepage (not recommended)" +msgstr "la page d’accueil (non conseillé)" + +#: includes/class-wc-trusted-shops-admin.php:435 +msgctxt "trusted-shops" +msgid "Rich snippets code" +msgstr "Code pour les Rich Snippets" + +#: includes/class-wc-trusted-shops-admin.php:447 +msgctxt "trusted-shops" +msgid "Configure your Product Reviews " +msgstr "Configurer les avis produits " + +#: includes/class-wc-trusted-shops-admin.php:448 +#, php-format +msgctxt "trusted-shops" +msgid "To use Product Reviews, activate them in your %s first." +msgstr "" +"Pour pouvoir utiliser les avis produits, veuillez d’abord activer l’option " +"%s." + +#: includes/class-wc-trusted-shops-admin.php:448 +msgctxt "trusted-shops" +msgid "Trusted Shops package" +msgstr "Services Trusted Shops" + +#: includes/class-wc-trusted-shops-admin.php:454 +msgctxt "trusted-shops" +msgid "Collect Product Reviews" +msgstr "Collecter des avis produits" + +#: includes/class-wc-trusted-shops-admin.php:455 +msgctxt "trusted-shops" +msgid "(WooCommerce Product Reviews will be replaced)" +msgstr "(Les avis produits WooCommerce seront remplacés)" + +#: includes/class-wc-trusted-shops-admin.php:456 +msgctxt "trusted-shops" +msgid "" +"Show Product Reviews on the product page in a separate tab, just as shown on " +"the picture on the right." +msgstr "Afficher les avis produits dans un onglet séparé sur la page produit." + +#: includes/class-wc-trusted-shops-admin.php:464 +msgctxt "trusted-shops" +msgid "Reviews" +msgstr "Avis clients" + +#: includes/class-wc-trusted-shops-admin.php:465 +#: includes/class-wc-trusted-shops-admin.php:474 +msgctxt "trusted-shops" +msgid "You can choose a name for the tab with your Product Reviews." +msgstr "" +"Vous pouvez choisir le nom de l’onglet dans lequel vous souhaitez afficher " +"vos avis produits." + +#: includes/class-wc-trusted-shops-admin.php:466 +msgctxt "trusted-shops" +msgid "Show Product Reviews on the product detail page in an additional tab." +msgstr "Afficher les avis produits dans un onglet séparé sur la page produit." + +#: includes/class-wc-trusted-shops-admin.php:473 +msgctxt "trusted-shops" +msgid "Name of Product Reviews tab" +msgstr "Nom de l’onglet" + +#: includes/class-wc-trusted-shops-admin.php:477 +msgctxt "trusted-shops" +msgid "Product reviews" +msgstr "Avis produits" + +#: includes/class-wc-trusted-shops-admin.php:481 +msgctxt "trusted-shops" +msgid "Border color" +msgstr "Couleur du cadre" + +#: includes/class-wc-trusted-shops-admin.php:482 +msgctxt "trusted-shops" +msgid "Set the color for the frame around your Product Reviews." +msgstr "Choisir la couleur du cadre des avis produits." + +#: includes/class-wc-trusted-shops-admin.php:490 +msgctxt "trusted-shops" +msgid "Set the background color for your Product Reviews." +msgstr "Choisir la couleur de l’arrière-plan des avis produits." + +#: includes/class-wc-trusted-shops-admin.php:497 +#: includes/class-wc-trusted-shops-admin.php:547 +msgctxt "trusted-shops" +msgid "Star color" +msgstr "Couleur des étoiles" + +#: includes/class-wc-trusted-shops-admin.php:498 +msgctxt "trusted-shops" +msgid "Set the color for the Product Review stars in your Product Reviews tab." +msgstr "" +"Choisi la couleur des étoiles qui seront affichées dans l’onglet avec les " +"avis produits." + +#: includes/class-wc-trusted-shops-admin.php:505 +#: includes/class-wc-trusted-shops-admin.php:555 +msgctxt "trusted-shops" +msgid "Star size" +msgstr "Dimension des étoiles" + +#: includes/class-wc-trusted-shops-admin.php:510 +msgctxt "trusted-shops" +msgid "Set the size for the Product Review stars in your Product Reviews tab." +msgstr "" +"Choisir la dimension des étoiles qui seront affichées dans l’onglet avec les " +"avis produits." + +#: includes/class-wc-trusted-shops-admin.php:521 +msgctxt "trusted-shops" +msgid "Product Sticker Code" +msgstr "Code des vignettes avis produits" + +#: includes/class-wc-trusted-shops-admin.php:530 +#: includes/class-wc-trusted-shops-admin.php:596 +msgctxt "trusted-shops" +msgid "jQuerySelector" +msgstr "jQuerySelector" + +#: includes/class-wc-trusted-shops-admin.php:531 +msgctxt "trusted-shops" +msgid "" +"Please choose where your Product Reviews shall be displayed on the Product " +"detail page." +msgstr "" +"Veuillez choisir l’endroit où les Avis Produits seront affichés sur la page " +"produit" + +#: includes/class-wc-trusted-shops-admin.php:538 +msgctxt "trusted-shops" +msgid "Rating stars" +msgstr "Étoiles d’évaluation" + +#: includes/class-wc-trusted-shops-admin.php:539 +msgctxt "trusted-shops" +msgid "Show star ratings on the product detail page below your product name." +msgstr "" +"Afficher les étoiles d’évaluation sur la page produit en dessous du nom du " +"produit." + +#: includes/class-wc-trusted-shops-admin.php:540 +msgctxt "trusted-shops" +msgid "" +"Display Product Review stars on product pages below the product name, just " +"as shown in the picture on the right." +msgstr "" +"Afficher les étoiles d’évaluation sur la page produit en dessous du nom du " +"produit, comme illustré par l’image ci-contre." + +#: includes/class-wc-trusted-shops-admin.php:549 +msgctxt "trusted-shops" +msgid "" +"Set the color for the review stars, that are displayed on the product page, " +"below your product name." +msgstr "" +"Choisir la couleur des étoiles qui seront affichées sur la page produit en " +"dessous du nom du produit." + +#: includes/class-wc-trusted-shops-admin.php:557 +msgctxt "trusted-shops" +msgid "" +"Set the size for the review stars that are displayed on the product page, " +"below your product name." +msgstr "" +"Choisir la dimension des étoiles qui seront affichées sur la page produit en " +"dessous du nom du produit." + +#: includes/class-wc-trusted-shops-admin.php:571 +msgctxt "trusted-shops" +msgid "Font size" +msgstr "Taille de la police" + +#: includes/class-wc-trusted-shops-admin.php:573 +msgctxt "trusted-shops" +msgid "Set the font size for the text that goes with your review stars." +msgstr "" +"Choisir la taille de la police du texte correspondant à vos étoiles " +"d’évaluation." + +#: includes/class-wc-trusted-shops-admin.php:587 +msgctxt "trusted-shops" +msgid "Product Review Code" +msgstr "Code pour les étoiles d’évaluation" + +#: includes/class-wc-trusted-shops-admin.php:597 +msgctxt "trusted-shops" +msgid "" +"Please choose where your Product Review Stars shall be displayed on the " +"Product Detail page." +msgstr "" +"Veuillez choisir l’endroit où les étoiles des Avis Produit seront affichées " +"sur la page produit" + +#: includes/class-wc-trusted-shops-admin.php:604 +msgctxt "trusted-shops" +msgid "Brand attribute" +msgstr "Attribut marque" + +#: includes/class-wc-trusted-shops-admin.php:605 +#, php-format +msgctxt "trusted-shops" +msgid "Create brand attribute %s" +msgstr "Créer %s un attribut marque" + +#: includes/class-wc-trusted-shops-admin.php:606 +msgctxt "trusted-shops" +msgid "" +"Brand name of the product. By passing this information on to Google, you " +"improve your chances of having Google identify your products. Assign your " +"brand attribute. If your products don't have a GTIN, you can pass on the " +"brand name and the MPN to use Google Integration." +msgstr "" +"Nom de la marque du produit. En indiquant cette variable, il est plus " +"probable que Google identifie clairement vos produits. Veuillez assigner " +"l’attribut marque ici. Si vos produits n’ont pas de GTIN, vous pouvez " +"indiquer le nom de la marque ainsi que le MPN pour utiliser l’intégration " +"Google." + +#: includes/class-wc-trusted-shops-admin.php:612 +msgctxt "trusted-shops" +msgid "None" +msgstr "Aucun" + +#: includes/class-wc-trusted-shops-admin.php:623 +msgctxt "trusted-shops" +msgid "Configure your Review Requests" +msgstr "Configurer vos rappels d’avis" + +#: includes/class-wc-trusted-shops-admin.php:624 +msgctxt "trusted-shops" +msgid "" +"7 days after an order has been placed, Trusted Shops automatically sends an " +"invite to your customers. If you want to set a different time for sending " +"automatic Review Requests, please activate the option below. If you want to " +"send review requests with legal certainty, you need your customers' consent " +"to receive Review Requests. You also have to include an option to " +"unsubscribe." +msgstr "" +"Trusted Shops envoie automatiquement un rappel d’avis à vos clients 7 jours " +"après leur commande. Si vous préférez décider vous-même du moment auquel " +"vous souhaitez envoyer vos demandes d’avis, cochez l’option ci-dessous. Pour " +"envoyer des rappels d’avis en conformité avec la loi, il faut obtenir le " +"consentement exprès des clients à la réception d’e-mails de demande d’avis. " +"Vous devez également donner à vos clients un moyen de se désabonner des " +"rappels d’avis." + +#: includes/class-wc-trusted-shops-admin.php:630 +msgctxt "trusted-shops" +msgid "Enable Review Requests" +msgstr "Activer les demandes d’avis" + +#: includes/class-wc-trusted-shops-admin.php:639 +msgctxt "trusted-shops" +msgid "WooCommerce status" +msgstr "État de la commande" + +#: includes/class-wc-trusted-shops-admin.php:640 +msgctxt "trusted-shops" +msgid "" +"We recommend choosing the order status that you set when your products have " +"been shipped." +msgstr "" +"Sélectionner l’état de la commande que vous avez défini au moment de l’envoi " +"de la commande." + +#: includes/class-wc-trusted-shops-admin.php:648 +msgctxt "trusted-shops" +msgid "Days until Review Request" +msgstr "Jours avant envoi du rappel" + +#: includes/class-wc-trusted-shops-admin.php:649 +msgctxt "trusted-shops" +msgid "" +"Set the number of days to wait after an order has reached the order status " +"you selected above before having a review request sent to your customers." +msgstr "" +"Indiquer ici après combien de jours le rappel d’évaluation est envoyé à " +"l’acheteur après avoir atteint l’état de la commande sélectionné ci-dessus." + +#: includes/class-wc-trusted-shops-admin.php:661 +msgctxt "trusted-shops" +msgid "Permission via checkbox" +msgstr "Consentement par case à cocher" + +#: includes/class-wc-trusted-shops-admin.php:662 +msgctxt "trusted-shops" +msgid "" +"If the checkbox is activated, only customers who gave their consent will " +"receive Review Requests." +msgstr "" +"Si la case est cochée, seuls les clients ayant donné leur consentement " +"recevront un rappel d’avis par e-mail." + +#: includes/class-wc-trusted-shops-admin.php:666 +msgctxt "trusted-shops" +msgid "Edit checkbox" +msgstr "Modifier la case à cocher" + +#: includes/class-wc-trusted-shops-admin.php:670 +msgctxt "trusted-shops" +msgid "Unsubscribe via link" +msgstr "Désinscription via lien" + +#: includes/class-wc-trusted-shops-admin.php:671 +msgctxt "trusted-shops" +msgid "Allows the customer to unsubscribe from Review Requests." +msgstr "" +"Cette option permet aux clients de se désabonner des rappels d’avis en " +"cliquant sur un lien." + +#: includes/class-wc-trusted-shops-admin.php:772 +msgctxt "trusted-shops" +msgid "How does Trusted Shops make your shop better?" +msgstr "" +"En quoi les produits Trusted Shops contribuent-ils à optimiser votre " +"boutique en ligne?" + +#: includes/class-wc-trusted-shops-admin.php:774 +msgctxt "trusted-shops" +msgid "Get your account" +msgstr "Créer un compte" + +#: includes/class-wc-trusted-shops-admin.php:794 +msgctxt "trusted-shops" +msgid "Product Reviews on the product detail page in an additional tab" +msgstr "Avis produits dans l’onglet sur la page produit" + +#: includes/class-wc-trusted-shops-admin.php:797 +msgctxt "trusted-shops" +msgid "Show Star-Ratings on the product detail page below your product name" +msgstr "Étoiles d’évaluation sur la page produit en dessous du nom du produit" + +#: includes/class-wc-trusted-shops-admin.php:801 +msgctxt "trusted-shops" +msgid "" +"Please note: If you want to send review requests through WooCommerce, you " +"should deactivate automated review requests through Trusted Shops. To do so, " +"please go to your My Trusted Shops account. Log in and go to Reviews > " +"Settings and deactivate \"Collect reviews automatically\"" +msgstr "" +"Veuillez noter : Si vous souhaitez envoyer des rappels d’avis via " +"WooCommerce, vous devez désactiver l’envoi de rappels d’avis automatiques " +"via Trusted Shops. Pour ce faire, rendez-vous dans votre compte My Trusted " +"Shops. Connectez-vous à votre compte, cliquez sur Avis clients > " +"Configuration > Collecter les avis et désactivez l’option « Collecter des " +"avis automatiquement »." + +#: includes/class-wc-trusted-shops-admin.php:802 +msgctxt "trusted-shops" +msgid "To your My Trusted Shops account" +msgstr "Aller au compte My Trusted Shops" + +#: includes/class-wc-trusted-shops-admin.php:806 +msgctxt "trusted-shops" +msgid "" +"Export your customer information here and upload it in the Trusted Shops " +"Review Collector. To do so go to your My Trusted Shops account. Log in and " +"go to Reviews > Shop Reviews > Review Collector" +msgstr "" +"Exporter les données de vos clients et de vos commandes des x derniers jours " +"et importez-les dans votre compte My Trusted Shops" + +#: includes/class-wc-trusted-shops-admin.php:807 +msgctxt "trusted-shops" +msgid "To the Trusted Shops Review Collector" +msgstr "Aller au collecteur d’avis Trusted Shops" + +#: includes/class-wc-trusted-shops-admin.php:889 +msgctxt "trusted-shops" +msgid "Review Collector" +msgstr "Collecteur d’avis Trusted Shops" + +#: includes/class-wc-trusted-shops-admin.php:891 +#, php-format +msgctxt "trusted-shops" +msgid "" +"Want to collect reviews for orders that were placed before your Trusted " +"Shops Integration? No problem. Export old orders here and upload them in " +"your %s." +msgstr "" +"Vous souhaitez demander à des clients de laisser un avis sur des commandes " +"qu’ils ont passées avant l’intégration de Trusted Shops sur votre site ? Pas " +"de problème! Exportez les commandes passées et importez-les dans votre %s." + +#: includes/class-wc-trusted-shops-admin.php:891 +msgctxt "trusted-shops" +msgid "My Trusted Shops account" +msgstr "Compte My Trusted Shops" + +#: includes/class-wc-trusted-shops-admin.php:897 +msgctxt "trusted-shops" +msgid "Export orders" +msgstr "Exporter les commandes" + +#: includes/class-wc-trusted-shops-admin.php:897 +msgctxt "trusted-shops" +msgid "" +"Export your customer and order information of the last x days and upload " +"them in your My Trusted Shops Account." +msgstr "" +"Exporter les données de vos clients et de vos commandes des x derniers jours " +"et importez-les dans votre compte My Trusted Shops." + +#: includes/class-wc-trusted-shops-admin.php:901 +msgctxt "trusted-shops" +msgid "30 days" +msgstr "30 jours" + +#: includes/class-wc-trusted-shops-admin.php:902 +msgctxt "trusted-shops" +msgid "60 days" +msgstr "60 jours" + +#: includes/class-wc-trusted-shops-admin.php:903 +msgctxt "trusted-shops" +msgid "90 days" +msgstr "90 jours" + +#: includes/class-wc-trusted-shops-admin.php:905 +#, php-format +msgctxt "trusted-shops" +msgid "Upload customer and order information %s." +msgstr "Cliquez %s pour importer les données de vos clients." + +#: includes/class-wc-trusted-shops-admin.php:908 +msgctxt "trusted-shops" +msgid "Days until reminder mail" +msgstr "Jours avant envoi du rappel" + +#: includes/class-wc-trusted-shops-admin.php:908 +msgctxt "trusted-shops" +msgid "" +"Set the number of days to wait after the order date before having a Review " +"Request sent to your customers." +msgstr "" +"Indiquer ici après combien de jours le rappel d’évaluation est envoyé à " +"l’acheteur après avoir atteint l’état de la commande sélectionné ci-dessus." + +#: includes/class-wc-trusted-shops-admin.php:912 +msgctxt "trusted-shops" +msgid "Start export" +msgstr "Débuter l’exportation" + +#: includes/class-wc-trusted-shops-review-exporter.php:64 +msgctxt "trusted-shops" +msgid "Order ID" +msgstr "Réf. commande" + +#: includes/class-wc-trusted-shops-review-exporter.php:65 +msgctxt "trusted-shops" +msgid "Order date" +msgstr "Date de la commande" + +#: includes/class-wc-trusted-shops-review-exporter.php:66 +msgctxt "trusted-shops" +msgid "# Days" +msgstr "# Jours" + +#: includes/class-wc-trusted-shops-review-exporter.php:67 +msgctxt "trusted-shops" +msgid "Email" +msgstr "Email" + +#: includes/class-wc-trusted-shops-review-exporter.php:68 +msgctxt "trusted-shops" +msgid "First name" +msgstr "Prénom" + +#: includes/class-wc-trusted-shops-review-exporter.php:69 +msgctxt "trusted-shops" +msgid "Last name" +msgstr "Nom" + +#: includes/class-wc-trusted-shops-template-hooks.php:121 +#, php-format +msgctxt "trusted-shops" +msgid "" +"Your review reminder e-mail has been cancelled successfully. Return to %s." +msgstr "" +"Votre e-mail de demande d’avis a été annulé avec succès. Retourner à %s." + +#: includes/class-wc-trusted-shops-template-hooks.php:121 +msgctxt "trusted-shops" +msgid "Home" +msgstr "Accueil" + +#: includes/class-wc-trusted-shops-template-hooks.php:193 +msgctxt "trusted-shops" +msgid "" +"Yes, I would like to be reminded via e-mail after {days} day(s) to review my " +"order. I am able to cancel the reminder at any time by clicking on the " +"\"cancel review reminder\" link within the order confirmation." +msgstr "" +"Oui, je souhaite recevoir un demande d’avis par e-mail au bout de {days} " +"jour(s) pour évaluer ma commande. Je peux annuler le rappel à tout moment en " +"cliquant sur le lien Annuler le rappel d’évaluation dans l’email de " +"confirmation de commande." + +#: includes/class-wc-trusted-shops-template-hooks.php:198 +msgctxt "trusted-shops" +msgid "Please allow us to send a review reminder by e-mail." +msgstr "" +"Veuillez nous autoriser à vous envoyer un rappel d’évaluation par e-mail." + +#: includes/class-wc-trusted-shops-template-hooks.php:201 +msgctxt "trusted-shops" +msgid "Review reminder" +msgstr "Demande d’avis" + +#: includes/class-wc-trusted-shops-template-hooks.php:202 +msgctxt "trusted-shops" +msgid "Asks the customer to receive a Trusted Shops review reminder." +msgstr "Demande au client s’il veut recevoir une demande d’avis Trusted Shops." + +#: includes/class-wc-ts-dependencies.php:36 +#: includes/class-wc-ts-dependencies.php:45 woocommerce-trusted-shops.php:67 +#: woocommerce-trusted-shops.php:76 +msgid "Cheatin’ huh?" +msgstr "Cheatin’ huh?" + +#: includes/class-wc-ts-install.php:72 +#, php-format +msgid "" +"Please install WooCommerce before " +"installing WooCommerce Germanized. Thank you!" +msgstr "" +"Please install WooCommerce before " +"installing WooCommerce Germanized. Thank you!" + +#: includes/class-wc-ts-settings-handler.php:23 +msgctxt "trusted-shops" +msgid "Trusted Shops" +msgstr "Trusted Shops" + +#: includes/emails/class-wc-ts-email-customer-trusted-shops.php:25 +msgctxt "trusted-shops" +msgid "Trusted Shops Review Reminder" +msgstr " demande d’avis Trusted Shops" + +#: includes/emails/class-wc-ts-email-customer-trusted-shops.php:26 +msgctxt "trusted-shops" +msgid "" +"This E-Mail is being sent to a customer to remind him about the possibility " +"to leave a review at Trusted Shops." +msgstr "" +"Cet e-mail est envoyé à un client pour lui rappeler qu’il peut laisser un " +"avis via Trusted Shops." + +#: includes/emails/class-wc-ts-email-customer-trusted-shops.php:53 +msgctxt "trusted-shops" +msgid "Please rate your {site_title} order from {order_date}" +msgstr "" +"Veuillez évaluer votre commande sur la boutique {site_title} datant du " +"{order_date}" + +#: includes/emails/class-wc-ts-email-customer-trusted-shops.php:63 +msgctxt "trusted-shops" +msgid "Please rate your Order" +msgstr "Veuillez évaluer votre commande" + +#: includes/widgets/class-wc-trusted-shops-widget-review-sticker.php:19 +msgctxt "trusted-shops" +msgid "Show your TS shop review sticker." +msgstr "Afficher la vignette avis site" + +#: includes/widgets/class-wc-trusted-shops-widget-review-sticker.php:21 +msgctxt "trusted-shops" +msgid "Trusted Shops Shop Review Sticker" +msgstr "Vignette avis site" + +#: includes/widgets/class-wc-trusted-shops-widget-review-sticker.php:25 +#: includes/widgets/class-wc-trusted-shops-widget-review-sticker.php:46 +msgctxt "trusted-shops" +msgid "Trusted Shops Reviews" +msgstr "avis clients Trusted Shops" + +#: includes/widgets/class-wc-trusted-shops-widget-review-sticker.php:26 +msgctxt "trusted-shops" +msgid "Title" +msgstr "Titre" + +#: templates/emails/customer-trusted-shops.php:18 +#: templates/emails/plain/customer-trusted-shops.php:12 +#, php-format +msgctxt "trusted-shops" +msgid "Dear %s %s," +msgstr "Bonjour %s %s," + +#: templates/emails/customer-trusted-shops.php:19 +#: templates/emails/plain/customer-trusted-shops.php:14 +#, php-format +msgctxt "trusted-shops" +msgid "" +"You have recently shopped at %s. Thank you! We would be glad if you spent " +"some time to write a review about your order. To do so please follow follow " +"the link." +msgstr "" +"Vous avez récemment passé commande sur %s. Merci beaucoup! Nous serions " +"ravis si vous preniez quelques minutes afin de donner votre avis sur votre " +"commande. Veuillez pour cela cliquer sur le lien suivant." + +#: templates/emails/customer-trusted-shops.php:22 +msgctxt "trusted-shops" +msgid "Rate Order now" +msgstr "Évaluer ma commande maintenant" + +#: woocommerce-trusted-shops.php:220 +msgctxt "trusted-shops" +msgid "Yes" +msgstr "Oui" + +#: woocommerce-trusted-shops.php:220 +msgctxt "trusted-shops" +msgid "No" +msgstr "Non" + +#: woocommerce-trusted-shops.php:265 +#, php-format +msgctxt "trusted-shops" +msgid "" +"If the App helped you, please leave a %s★★" +"★★★%s in the Wordpress plugin repository." +msgstr "" +"If the App helped you, please leave a %s★★" +"★★★%s in the Wordpress plugin repository." + +#: woocommerce-trusted-shops.php:419 +msgctxt "trusted-shops" +msgid "Settings" +msgstr "Paramètres" diff --git a/packages/woocommerce-trusted-shops/includes/abstracts/abstract-wc-ts-compatibility.php b/packages/woocommerce-trusted-shops/includes/abstracts/abstract-wc-ts-compatibility.php new file mode 100644 index 000000000..d3b3731d8 --- /dev/null +++ b/packages/woocommerce-trusted-shops/includes/abstracts/abstract-wc-ts-compatibility.php @@ -0,0 +1,87 @@ + '1.0.0', + 'requires_at_least' => '', + 'tested_up_to' => '', + ) + ); + + if ( empty( $version_data['requires_at_least'] ) && empty( $version_data['tested_up_to'] ) ) { + $version_data['requires_at_least'] = $version_data['version']; + $version_data['tested_up_to'] = $version_data['version']; + } elseif ( empty( $version_data['tested_up_to'] ) ) { + $version_data['tested_up_to'] = $version_data['requires_at_least']; + if ( WC_TS_Dependencies::instance()->compare_versions( $version_data['version'], $version_data['requires_at_least'], '>' ) ) { + $version_data['tested_up_to'] = $version_data['version']; + } + } elseif ( empty( $version_data['requires_at_least'] ) ) { + $version_data['requires_at_least'] = $version_data['tested_up_to']; + if ( WC_TS_Dependencies::instance()->compare_versions( $version_data['version'], $version_data['requires_at_least'], '<' ) ) { + $version_data['requires_at_least'] = $version_data['version']; + } + } + + $this->version_data = $version_data; + + $this->plugin_name = $plugin_name; + $this->plugin_file = $plugin_file; + + if ( ! $this->is_applicable() ) { + return; + } + + add_action( 'init', array( $this, 'early_execution' ), 0 ); + add_action( 'init', array( $this, 'load' ), 15 ); + + $this->after_plugins_loaded(); + } + + public function early_execution() {} + + public function after_plugins_loaded() {} + + public function is_applicable() { + return $this->is_activated() && $this->is_supported(); + } + + public function is_activated() { + return WC_TS_Dependencies::instance()->is_plugin_activated( $this->plugin_file ); + } + + public function is_supported() { + return WC_TS_Dependencies::instance()->compare_versions( $this->version_data['version'], $this->version_data['requires_at_least'], '>=' ) && + WC_TS_Dependencies::instance()->compare_versions( $this->version_data['version'], $this->version_data['tested_up_to'], '<=' ); + } + + public function get_name() { + return $this->plugin_name; + } + + public function get_version_data() { + return $this->version_data; + } + + abstract public function load(); +} diff --git a/packages/woocommerce-trusted-shops/includes/admin/settings/class-wc-ts-gzd-settings-tab.php b/packages/woocommerce-trusted-shops/includes/admin/settings/class-wc-ts-gzd-settings-tab.php new file mode 100644 index 000000000..e92f88de7 --- /dev/null +++ b/packages/woocommerce-trusted-shops/includes/admin/settings/class-wc-ts-gzd-settings-tab.php @@ -0,0 +1,99 @@ +trusted_shops->get_dependency( 'admin' ); + + return $admin->get_trusted_url( 'https://support.trustedshops.com/en/apps/woocommerce' ); + } + + public function before_output() { + do_action( 'woocommerce_ts_admin_settings_before', $this->get_settings_for_section_core( '' ) ); + } + + public function review_exporter() { + $admin = WC_trusted_shops()->trusted_shops->get_dependency( 'admin' ); + $admin->review_collector_export(); + } + + public function register_scripts() { + if ( isset( $_GET['tab'] ) && 'germanized-trusted_shops' === $_GET['tab'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + do_action( 'woocommerce_trusted_shops_load_admin_scripts' ); + } + } + + public function get_description() { + return _x( 'Setup your Trusted Shops Integration.', 'trusted-shops', 'woocommerce-germanized' ); + } + + public function get_label() { + return _x( 'Trusted Shops', 'trusted-shops', 'woocommerce-germanized' ); + } + + public function get_name() { + return 'trusted_shops'; + } + + protected function output_description() {} + + public function get_tab_settings( $current_section = '' ) { + $admin = WC_trusted_shops()->trusted_shops->get_dependency( 'admin' ); + $settings = $admin->get_settings(); + + return $settings; + } + + public function get_sidebar( $current_section = '' ) { + $admin = WC_trusted_shops()->trusted_shops->get_dependency( 'admin' ); + $sidebar = $admin->get_sidebar(); + + return $sidebar; + } + + protected function get_enable_option_name() { + $option_prefix = Package::is_integration() ? 'gzd_' : ''; + $option_name = 'woocommerce_' . $option_prefix . 'trusted_shops_id'; + + return $option_name; + } + + public function is_enabled() { + $value = get_option( $this->get_enable_option_name() ); + + return ( ! empty( $value ) ? true : false ); + } + + protected function before_save( $settings, $current_section = '' ) { + do_action( 'woocommerce_ts_before_save', $settings ); + + parent::before_save( $settings, $current_section ); + } + + protected function after_save( $settings, $current_section = '' ) { + do_action( 'woocommerce_ts_after_save', $settings ); + + parent::after_save( $settings, $current_section ); + } +} diff --git a/packages/woocommerce-trusted-shops/includes/admin/views/html-notice-dependencies.php b/packages/woocommerce-trusted-shops/includes/admin/views/html-notice-dependencies.php new file mode 100644 index 000000000..059b5387e --- /dev/null +++ b/packages/woocommerce-trusted-shops/includes/admin/views/html-notice-dependencies.php @@ -0,0 +1,58 @@ + + +
+

+ plugins_required as $plugin => $data ) : // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited ?> + + is_plugin_activated( $plugin ) ) : + $missing_count++; + ?> + + + +

+ + + +

+ + + + is_plugin_outdated( $plugin ) ) : + $version_count ++; + ?> + +

+ + +

- ' . esc_html( $data['version'] ) . '' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>

+ + + + + + 0 ) : ?> + +

+ + + +

+ + + +
diff --git a/packages/woocommerce-trusted-shops/includes/admin/views/html-notice-update.php b/packages/woocommerce-trusted-shops/includes/admin/views/html-notice-update.php new file mode 100644 index 000000000..2d2b4923b --- /dev/null +++ b/packages/woocommerce-trusted-shops/includes/admin/views/html-notice-update.php @@ -0,0 +1,20 @@ + +
+

WooCommerce Trusted Shops Data Update Required – We just need to update your installation to the latest version', 'trusted-shops', 'woocommerce-germanized' ) ); ?>

+

+
+ diff --git a/packages/woocommerce-trusted-shops/includes/admin/views/html-settings-section.php b/packages/woocommerce-trusted-shops/includes/admin/views/html-settings-section.php new file mode 100644 index 000000000..f89cf2358 --- /dev/null +++ b/packages/woocommerce-trusted-shops/includes/admin/views/html-settings-section.php @@ -0,0 +1,44 @@ + +
+
+ + + +
+ + +
+ +
+ +
diff --git a/packages/woocommerce-trusted-shops/includes/admin/views/html-wpml-notice.php b/packages/woocommerce-trusted-shops/includes/admin/views/html-wpml-notice.php new file mode 100644 index 000000000..125338467 --- /dev/null +++ b/packages/woocommerce-trusted-shops/includes/admin/views/html-wpml-notice.php @@ -0,0 +1,20 @@ + + +
+

+

+ + + + ' . $current_language . '' ) ); ?> + +

+
diff --git a/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-admin.php b/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-admin.php new file mode 100644 index 000000000..9e8d21ed8 --- /dev/null +++ b/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-admin.php @@ -0,0 +1,1020 @@ +base = $base; + + add_action( 'woocommerce_ts_before_save', array( $this, 'before_save' ), 0, 1 ); + add_action( 'woocommerce_ts_after_save', array( $this, 'after_save' ), 0, 1 ); + + add_action( 'woocommerce_ts_admin_settings_before', array( $this, 'wpml_notice' ) ); + + // Default settings + add_filter( 'woocommerce_gzd_installation_default_settings', array( $this, 'set_installation_settings' ), 10, 1 ); + + // After Install + add_action( 'woocommerce_trusted_shops_installed', array( $this, 'create_attribute' ) ); + + // Review Collector + add_action( 'admin_init', array( $this, 'review_collector_export_csv' ) ); + add_action( 'woocommerce_trusted_shops_load_admin_scripts', array( $this, 'load_scripts' ) ); + + if ( ! \Vendidero\TrustedShops\Package::is_integration() ) { + add_action( 'woocommerce_product_options_general_product_data', array( $this, 'output_fields' ) ); + add_action( 'woocommerce_product_after_variable_attributes', array( $this, 'output_variation_fields' ), 20, 3 ); + add_action( 'woocommerce_save_product_variation', array( $this, 'save_variation_fields' ), 0, 2 ); + + if ( ! wc_ts_woocommerce_supports_crud() ) { + add_action( 'woocommerce_process_product_meta', array( $this, 'save_fields' ), 20, 2 ); + } else { + add_action( 'woocommerce_admin_process_product_object', array( $this, 'save_fields' ), 10, 1 ); + } + } + } + + public function set_installation_settings( $settings ) { + return array_merge( $settings, $this->get_settings() ); + } + + public function wpml_notice() { + if ( $this->base->is_multi_language_setup() ) { + $is_default_language = false; + $compatibility = $this->base->get_multi_language_compatibility(); + $default_language = strtoupper( $compatibility->get_default_language() ); + $current_language = strtoupper( $compatibility->get_current_language() ); + + if ( $current_language === $default_language ) { + $is_default_language = true; + } + + include_once 'admin/views/html-wpml-notice.php'; + } + } + + public function output_variation_fields( $loop, $variation_data, $variation ) { + $_product = wc_get_product( $variation ); + $_parent = wc_get_product( wc_ts_get_crud_data( $_product, 'parent' ) ); + $variation_id = wc_ts_get_crud_data( $_product, 'id' ); + $variation_meta = get_post_meta( $variation_id ); + $variation_data = array(); + + $variation_fields = array( + '_ts_gtin' => '', + '_ts_mpn' => '', + ); + + foreach ( $variation_fields as $field => $value ) { + $variation_data[ $field ] = isset( $variation_meta[ $field ][0] ) ? maybe_unserialize( $variation_meta[ $field ][0] ) : $value; + } + + ?> + +
+

+ + +

+

+ + +

+
+ + '', + '_ts_mpn' => '', + ); + + foreach ( $data as $k => $v ) { + $data_k = 'variable' . ( substr( $k, 0, 1 ) === '_' ? '' : '_' ) . $k; + $data[ $k ] = ( isset( $_POST[ $data_k ][ $i ] ) ? wc_clean( wp_unslash( $_POST[ $data_k ][ $i ] ) ) : null ); // phpcs:ignore WordPress.Security.NonceVerification.Missing + } + + if ( $product = wc_get_product( $variation_id ) ) { + foreach ( $data as $key => $value ) { + $product = wc_ts_set_crud_data( $product, $key, $value ); + } + + if ( wc_ts_woocommerce_supports_crud() ) { + $product->save(); + } + } + } + + public function output_fields() { + echo '
'; + + woocommerce_wp_text_input( + array( + 'id' => '_ts_gtin', + 'label' => _x( 'GTIN', 'trusted-shops', 'woocommerce-germanized' ), + 'data_type' => 'text', + 'desc_tip' => true, + 'description' => _x( + 'ID that allows your products to be identified worldwide. If you want to display your Trusted Shops Product Reviews in Google Shopping and paid Google adverts, Google needs the GTIN.', + 'trusted-shops', + 'woocommerce-trusted-shops' + ), + ) + ); + woocommerce_wp_text_input( + array( + 'id' => '_ts_mpn', + 'label' => _x( 'MPN', 'trusted-shops', 'woocommerce-germanized' ), + 'data_type' => 'text', + 'desc_tip' => true, + 'description' => _x( + 'If you don\'t have a GTIN for your products, you can pass the brand name and the MPN on to Google to use the Trusted Shops Google Integration.', + 'trusted-shops', + 'woocommerce-trusted-shops' + ), + ) + ); + + echo '
'; + } + + public function save_fields( $product ) { + if ( is_numeric( $product ) ) { + $product = wc_get_product( $product ); + } + + if ( isset( $_POST['_ts_gtin'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing + $product = wc_ts_set_crud_data( $product, '_ts_gtin', wc_clean( wp_unslash( $_POST['_ts_gtin'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing + } + + if ( isset( $_POST['_ts_mpn'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing + $product = wc_ts_set_crud_data( $product, '_ts_mpn', wc_clean( wp_unslash( $_POST['_ts_mpn'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing + } + } + + public function create_attribute() { + $attributes = array( + 'brand' => _x( 'Brand', 'trusted-shops', 'woocommerce-germanized' ), + ); + + // Create the taxonomy + global $wpdb; + delete_transient( 'wc_attribute_taxonomies' ); + + foreach ( $attributes as $attribute_name => $title ) { + if ( ! in_array( 'pa_' . $attribute_name, wc_get_attribute_taxonomy_names(), true ) ) { + $attribute = array( + 'attribute_label' => $title, + 'attribute_name' => $attribute_name, + 'attribute_type' => 'text', + 'attribute_orderby' => 'menu_order', + 'attribute_public' => 0, + ); + + $wpdb->insert( $wpdb->prefix . 'woocommerce_attribute_taxonomies', $attribute ); + delete_transient( 'wc_attribute_taxonomies' ); + } + } + } + + public function load_scripts() { + $screen = get_current_screen(); + $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; + $assets_path = $this->base->plugin->plugin_url() . '/assets/'; + + wp_register_style( 'woocommerce-trusted-shops-admin', $assets_path . 'css/admin' . $suffix . '.css', false, $this->base->plugin->version ); + wp_enqueue_style( 'woocommerce-trusted-shops-admin' ); + + wp_register_script( 'wc-admin-trusted-shops', $assets_path . 'js/admin' . $suffix . '.js', array( 'jquery', 'woocommerce_settings' ), $this->base->plugin->version, true ); + wp_localize_script( + 'wc-admin-trusted-shops', + 'trusted_shops_params', + array( + 'option_prefix' => $this->base->option_prefix, + 'i18n_error_mandatory' => _x( 'This field is mandatory', 'trusted-shops', 'woocommerce-germanized' ), + ) + ); + + wp_enqueue_script( 'wc-admin-trusted-shops' ); + } + + public function register_section( $sections ) { + $sections['trusted_shops'] = _x( 'Trusted Shops Options', 'trusted-shops', 'woocommerce-germanized' ); + + return $sections; + } + + public function get_font_families() { + return array( + 'Arial' => _x( 'Arial', 'trusted-shops', 'woocommerce-germanized' ), + 'Geneva' => _x( 'Geneva', 'trusted-shops', 'woocommerce-germanized' ), + 'Georgia' => _x( 'Georgia', 'trusted-shops', 'woocommerce-germanized' ), + 'Helvetica' => _x( 'Helvetica', 'trusted-shops', 'woocommerce-germanized' ), + 'Sans-serif' => _x( 'Sans-serif', 'trusted-shops', 'woocommerce-germanized' ), + 'Serif' => _x( 'Serif', 'trusted-shops', 'woocommerce-germanized' ), + 'Trebuchet MS' => _x( 'Trebuchet MS', 'trusted-shops', 'woocommerce-germanized' ), + 'Verdana' => _x( 'Verdana', 'trusted-shops', 'woocommerce-germanized' ), + ); + } + + public function get_order_statuses() { + return wc_get_order_statuses(); + } + + public function get_translatable_settings() { + $translatable = array(); + + foreach ( $this->get_settings_array() as $setting ) { + if ( isset( $setting['id'] ) && ! in_array( $setting['type'], array( 'title', 'sectionend' ), true ) ) { + $translatable[ $setting['id'] ] = ''; + } + } + + return $translatable; + } + + protected function get_settings_array( $defaults = array() ) { + $settings = array( + array( + 'title' => _x( 'Trusted Shops Integration', 'trusted-shops', 'woocommerce-germanized' ), + 'desc' => sprintf( _x( 'Do you need help with integrating your Trustbadge? %s', 'trusted-shops', 'woocommerce-germanized' ), '' . _x( 'To the step-by-step instructions', 'trusted-shops', 'woocommerce-germanized' ) . '' ), + 'type' => 'title', + 'id' => 'trusted_shops_options', + ), + + array( + 'title' => _x( 'Trusted Shops ID', 'trusted-shops', 'woocommerce-germanized' ), + 'desc' => _x( 'The Trusted Shops ID is a unique identifier for your shop. You can find your Trusted Shops ID in your My Trusted Shops account.', 'trusted-shops', 'woocommerce-germanized' ), + 'desc_tip' => true, + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_id', + 'type' => 'text', + 'custom_attributes' => array( 'data-sidebar' => 'wc-ts-sidebar-default' ), + 'css' => 'min-width:300px;', + ), + + array( + 'title' => _x( 'Edit Mode', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_integration_mode', + 'desc_tip' => _x( 'The advanced configuration is for users with programming skills. Here you can create even more individual settings.', 'trusted-shops', 'woocommerce-germanized' ), + 'type' => 'select', + 'class' => 'chosen_select', + 'options' => array( + 'standard' => _x( 'Standard configuration', 'trusted-shops', 'woocommerce-germanized' ), + 'expert' => _x( 'Advanced configuration', 'trusted-shops', 'woocommerce-germanized' ), + ), + 'default' => 'standard', + ), + + array( + 'type' => 'sectionend', + 'id' => 'trusted_shops_options', + ), + + array( + 'title' => _x( 'Configure your Trustbadge', 'trusted-shops', 'woocommerce-germanized' ), + 'type' => 'title', + 'id' => 'trusted_shops_badge_options', + ), + + array( + 'title' => _x( 'Display Trustbadge', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_trustbadge_enable', + 'desc_tip' => _x( 'Display the Trustbadge on all the pages of your shop.', 'trusted-shops', 'woocommerce-germanized' ), + 'type' => 'ts_toggle', + 'custom_attributes' => array( 'data-sidebar' => 'wc-ts-sidebar-trustbadge' ), + 'default' => 'no', + ), + + array( + 'title' => _x( 'Variant', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_trustbadge_variant', + 'desc_tip' => _x( 'You can display your Trustbadge with or without Review Stars.', 'trusted-shops', 'woocommerce-germanized' ), + 'type' => 'select', + 'class' => 'chosen_select', + 'options' => array( + 'standard' => _x( 'Display Trustbadge with review stars', 'trusted-shops', 'woocommerce-germanized' ), + 'hide_reviews' => _x( 'Display Trustbadge without review stars', 'trusted-shops', 'woocommerce-germanized' ), + ), + 'default' => 'standard', + ), + + array( + 'title' => _x( 'Vertical Offset', 'trusted-shops', 'woocommerce-germanized' ), + 'desc_tip' => _x( 'Choose the distance that the Trustbadge will appear from the bottom-right corner of the screen.', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_trustbadge_y', + 'type' => 'number', + 'desc' => _x( 'px', 'trusted-shops', 'woocommerce-germanized' ), + 'default' => '0', + 'custom_attributes' => array( + 'step' => '1', + 'min' => 0, + 'data-validate' => 'integer', + 'data-validate-msg' => sprintf( _x( 'Please choose a non-negative number (at least %d)', 'trusted-shops', 'woocommerce-germanized' ), 0 ), + ), + 'css' => 'max-width:60px;', + ), + + array( + 'title' => _x( 'Trustbadge code', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_trustbadge_code', + 'type' => 'textarea', + 'desc_tip' => true, + 'desc' => _x( 'The advanced configuration is for users with programming skills. Here you can create even more individual settings.', 'trusted-shops', 'woocommerce-germanized' ), + 'css' => 'width: 100%; min-height: 150px', + 'default' => '', + ), + + array( + 'type' => 'sectionend', + 'id' => 'trusted_shops_badge_options', + ), + + array( + 'title' => _x( 'Configure your Shop Reviews', 'trusted-shops', 'woocommerce-germanized' ), + 'type' => 'title', + 'id' => 'trusted_shops_review_sticker_options', + ), + + array( + 'title' => _x( 'Display Shop Review Sticker', 'trusted-shops', 'woocommerce-germanized' ), + 'desc_tip' => _x( 'To display the Shop Review Sticker, you have to assign the widget "Trusted Shops Review Sticker".', 'trusted-shops', 'woocommerce-germanized' ), + 'desc' => sprintf( _x( 'Assign widget %s', 'trusted-shops', 'woocommerce-germanized' ), '' . _x( 'here', 'trusted-shops', 'woocommerce-germanized' ) . '' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_review_sticker_enable', + 'type' => 'ts_toggle', + 'custom_attributes' => array( 'data-sidebar' => 'wc-ts-sidebar-shop-reviews' ), + 'default' => 'no', + ), + + array( + 'title' => _x( 'Background color', 'trusted-shops', 'woocommerce-germanized' ), + 'desc_tip' => _x( 'Choose the background color for your Review Sticker.', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_review_sticker_bg_color', + 'type' => 'color', + 'default' => '#FFDC0F', + ), + + array( + 'title' => _x( 'Font', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_review_sticker_font', + 'desc_tip' => _x( 'Choose the font for your Review Sticker.', 'trusted-shops', 'woocommerce-germanized' ), + 'type' => 'select', + 'class' => 'chosen_select', + 'default' => 'arial', + ), + + array( + 'title' => _x( 'Number of reviews displayed', 'trusted-shops', 'woocommerce-germanized' ), + 'desc_tip' => _x( 'Display x alternating Shop Reviews in your Shop Review Sticker. You can display between 1 and 5 alternating Shop Reviews.', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_review_sticker_number', + 'type' => 'number', + 'desc' => _x( 'Show x alternating reviews', 'trusted-shops', 'woocommerce-germanized' ), + 'default' => '5', + 'custom_attributes' => array( + 'step' => '1', + 'min' => 1, + 'max' => 5, + 'data-validate' => 'integer', + 'data-validate-msg' => sprintf( _x( 'Please choose a non-negative number between %1$d and %2$d', 'trusted-shops', 'woocommerce-germanized' ), 1, 5 ), + ), + 'css' => 'max-width:60px;', + ), + + array( + 'title' => _x( 'Minimum rating displayed', 'trusted-shops', 'woocommerce-germanized' ), + 'desc_tip' => _x( 'Only show Shop Reviews with a minimum rating of x stars. ', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_review_sticker_better_than', + 'type' => 'number', + 'desc' => _x( 'Star(s)', 'trusted-shops', 'woocommerce-germanized' ), + 'default' => '3', + 'custom_attributes' => array( + 'step' => '1', + 'min' => 1, + 'max' => 5, + 'data-validate' => 'integer', + 'data-validate-msg' => sprintf( _x( 'Please choose a non-negative number between %1$d and %2$d', 'trusted-shops', 'woocommerce-germanized' ), 1, 5 ), + ), + 'css' => 'max-width:60px;', + ), + + array( + 'title' => _x( 'Sticker code', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_review_sticker_code', + 'type' => 'textarea', + 'desc_tip' => true, + 'desc' => _x( 'The advanced configuration is for users with programming skills. Here you can perform even more individual settings.', 'trusted-shops', 'woocommerce-germanized' ), + 'css' => 'width: 100%; min-height: 150px', + 'default' => '', + ), + + array( + 'title' => _x( 'Google Organic Search', 'trusted-shops', 'woocommerce-germanized' ), + 'desc_tip' => _x( 'Activate this option to give Google the opportunity to show your Shop Reviews in Google organic search results.', 'trusted-shops', 'woocommerce-germanized' ), + 'desc' => _x( 'By activating this option, rich snippets will be integrated in the selected pages so your shop review stars may be displayed in Google organic search results. If you use Product Reviews and already activated rich snippets in expert mode, we recommend integrating rich snippets for Shop Reviews on category pages only.', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_rich_snippets_enable', + 'type' => 'ts_toggle', + 'default' => 'no', + ), + + array( + 'title' => _x( 'Activate rich snippets on', 'trusted-shops', 'woocommerce-germanized' ), + 'desc' => _x( 'category pages', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_rich_snippets_category', + 'type' => 'checkbox', + 'default' => 'no', + 'checkboxgroup' => 'start', + ), + + array( + 'desc' => _x( 'product pages', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_rich_snippets_product', + 'type' => 'checkbox', + 'default' => 'no', + 'checkboxgroup' => '', + ), + + array( + 'desc' => _x( 'homepage (not recommended)', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_rich_snippets_home', + 'type' => 'checkbox', + 'default' => 'no', + 'checkboxgroup' => 'end', + ), + + array( + 'title' => _x( 'Rich snippets code', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_rich_snippets_code', + 'type' => 'textarea', + 'desc_tip' => true, + 'desc' => _x( 'The advanced configuration is for users with programming skills. Here you can create even more individual settings.', 'trusted-shops', 'woocommerce-germanized' ), + 'css' => 'width: 100%; min-height: 150px', + 'default' => '', + ), + + array( + 'type' => 'sectionend', + 'id' => 'trusted_shops_review_sticker_options', + ), + + array( + 'title' => _x( 'Configure your Product Reviews ', 'trusted-shops', 'woocommerce-germanized' ), + 'desc' => sprintf( _x( 'To use Product Reviews, activate them in your %s first.', 'trusted-shops', 'woocommerce-germanized' ), '' . _x( 'Trusted Shops package', 'trusted-shops', 'woocommerce-germanized' ) . '' ), + 'type' => 'title', + 'id' => 'trusted_shops_reviews_options', + ), + + array( + 'title' => _x( 'Collect Product Reviews', 'trusted-shops', 'woocommerce-germanized' ), + 'desc' => _x( 'Show Product Reviews on the product page in a separate tab, just as shown on the picture on the right.', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_reviews_enable', + 'type' => 'ts_toggle', + 'custom_attributes' => array( 'data-sidebar' => 'wc-ts-sidebar-product-reviews' ), + 'default' => 'no', + ), + + array( + 'title' => _x( 'Reviews', 'trusted-shops', 'woocommerce-germanized' ), + 'desc_tip' => _x( 'You can choose a name for the tab with your Product Reviews.', 'trusted-shops', 'woocommerce-germanized' ), + 'desc' => _x( 'Show Product Reviews on the product detail page in an additional tab.', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_product_sticker_enable', + 'type' => 'ts_toggle', + 'default' => 'no', + ), + + array( + 'title' => _x( 'Name of Product Reviews tab', 'trusted-shops', 'woocommerce-germanized' ), + 'desc_tip' => _x( 'You can choose a name for the tab with your Product Reviews.', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_product_sticker_tab_text', + 'type' => 'text', + 'default' => _x( 'Product reviews', 'trusted-shops', 'woocommerce-germanized' ), + ), + + array( + 'title' => _x( 'Border color', 'trusted-shops', 'woocommerce-germanized' ), + 'desc_tip' => _x( 'Set the color for the frame around your Product Reviews.', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_product_sticker_border_color', + 'type' => 'color', + 'default' => '#FFDC0F', + ), + + array( + 'title' => _x( 'Background color', 'trusted-shops', 'woocommerce-germanized' ), + 'desc_tip' => _x( 'Set the background color for your Product Reviews.', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_product_sticker_bg_color', + 'type' => 'color', + 'default' => '#FFFFFF', + ), + + array( + 'title' => _x( 'Star color', 'trusted-shops', 'woocommerce-germanized' ), + 'desc_tip' => _x( 'Set the color for the Product Review stars in your Product Reviews tab.', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_product_sticker_star_color', + 'type' => 'color', + 'default' => '#C0C0C0', + ), + + array( + 'title' => _x( 'Star size', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_product_sticker_star_size', + 'type' => 'number', + 'default' => '15', + 'desc' => _x( 'px', 'trusted-shops', 'woocommerce-germanized' ), + 'desc_tip' => _x( 'Set the size for the Product Review stars in your Product Reviews tab.', 'trusted-shops', 'woocommerce-germanized' ), + 'css' => 'max-width:60px;', + 'custom_attributes' => array( + 'step' => '1', + 'min' => 0, + 'data-validate' => 'integer', + 'data-validate-msg' => sprintf( _x( 'Please choose a non-negative number (at least %d)', 'trusted-shops', 'woocommerce-germanized' ), 0 ), + ), + ), + + array( + 'title' => _x( 'Product Sticker Code', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_product_sticker_code', + 'desc_tip' => _x( 'The advanced configuration is for users with programming skills. Here you can perform even more individual settings.', 'trusted-shops', 'woocommerce-germanized' ), + 'type' => 'textarea', + 'css' => 'width: 100%; min-height: 150px', + 'default' => '', + ), + + array( + 'title' => _x( 'jQuerySelector', 'trusted-shops', 'woocommerce-germanized' ), + 'desc_tip' => _x( 'Please choose where your Product Reviews shall be displayed on the Product detail page.', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_product_sticker_selector', + 'type' => 'text', + 'default' => '#ts_product_sticker', + ), + + array( + 'title' => _x( 'Rating stars', 'trusted-shops', 'woocommerce-germanized' ), + 'desc' => _x( 'Show star ratings on the product detail page below your product name.', 'trusted-shops', 'woocommerce-germanized' ), + 'desc_tip' => _x( 'Display Product Review stars on product pages below the product name, just as shown in the picture on the right.', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_product_widget_enable', + 'type' => 'ts_toggle', + 'default' => 'no', + ), + + array( + 'title' => _x( 'Star color', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_product_widget_star_color', + 'desc_tip' => _x( 'Set the color for the review stars, that are displayed on the product page, below your product name.', 'trusted-shops', 'woocommerce-germanized' ), + 'type' => 'color', + 'default' => '#FFDC0F', + ), + + array( + 'title' => _x( 'Star size', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_product_widget_star_size', + 'desc_tip' => _x( 'Set the size for the review stars that are displayed on the product page, below your product name.', 'trusted-shops', 'woocommerce-germanized' ), + 'type' => 'number', + 'default' => '14', + 'desc' => _x( 'px', 'trusted-shops', 'woocommerce-germanized' ), + 'css' => 'max-width:60px;', + 'custom_attributes' => array( + 'step' => '1', + 'min' => 0, + 'data-validate' => 'integer', + 'data-validate-msg' => sprintf( _x( 'Please choose a non-negative number (at least %d)', 'trusted-shops', 'woocommerce-germanized' ), 0 ), + ), + ), + + array( + 'title' => _x( 'Font size', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_product_widget_font_size', + 'desc_tip' => _x( 'Set the font size for the text that goes with your review stars.', 'trusted-shops', 'woocommerce-germanized' ), + 'type' => 'number', + 'desc' => _x( 'px', 'trusted-shops', 'woocommerce-germanized' ), + 'default' => '12', + 'css' => 'max-width:60px;', + 'custom_attributes' => array( + 'step' => '1', + 'min' => 0, + 'data-validate' => 'integer', + 'data-validate-msg' => sprintf( _x( 'Please choose a non-negative number (at least %d)', 'trusted-shops', 'woocommerce-germanized' ), 0 ), + ), + ), + + array( + 'title' => _x( 'Product Review Code', 'trusted-shops', 'woocommerce-germanized' ), + 'desc_tip' => _x( 'The advanced configuration is for users with programming skills. Here you can perform even more individual settings.', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_product_widget_code', + 'type' => 'textarea', + 'css' => 'width: 100%; min-height: 150px', + 'default' => '', + ), + + array( + 'title' => _x( 'jQuerySelector', 'trusted-shops', 'woocommerce-germanized' ), + 'desc_tip' => _x( 'Please choose where your Product Review Stars shall be displayed on the Product Detail page.', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_product_widget_selector', + 'type' => 'text', + 'default' => '#ts_product_widget', + ), + + array( + 'title' => _x( 'Brand attribute', 'trusted-shops', 'woocommerce-germanized' ), + 'desc' => sprintf( _x( 'Create brand attribute %s', 'trusted-shops', 'woocommerce-germanized' ), '' . _x( 'here', 'trusted-shops', 'woocommerce-germanized' ) . '' ), + 'desc_tip' => _x( 'Brand name of the product. By passing this information on to Google, you improve your chances of having Google identify your products. Assign your brand attribute. If your products don\'t have a GTIN, you can pass on the brand name and the MPN to use Google Integration.', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_brand_attribute', + 'css' => 'min-width:250px;', + 'default' => 'brand', + 'type' => 'select', + 'class' => 'chosen_select_nostd', + 'custom_attributes' => array( 'data-placeholder' => _x( 'None', 'trusted-shops', 'woocommerce-germanized' ) ), + ), + + array( + 'type' => 'sectionend', + 'id' => 'trusted_shops_reviews_options', + ), + ); + + if ( $this->base->supports( 'reminder' ) ) { + + $settings = array_merge( + $settings, + array( + + array( + 'title' => _x( 'Configure your Review Requests', 'trusted-shops', 'woocommerce-germanized' ), + 'desc' => _x( '7 days after an order has been placed, Trusted Shops automatically sends an invite to your customers. If you want to set a different time for sending automatic Review Requests, please activate the option below. If you want to send review requests with legal certainty, you need your customers\' consent to receive Review Requests. You also have to include an option to unsubscribe.', 'trusted-shops', 'woocommerce-germanized' ), + 'type' => 'title', + 'id' => 'trusted_shops_review_reminder_options', + ), + + array( + 'title' => _x( 'Enable Review Requests', 'trusted-shops', 'woocommerce-germanized' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_review_reminder_enable', + 'type' => 'ts_toggle', + 'default' => 'no', + 'custom_attributes' => array( 'data-sidebar' => 'wc-ts-sidebar-review-reminder' ), + 'autoload' => false, + ), + + array( + 'title' => _x( 'WooCommerce status', 'trusted-shops', 'woocommerce-germanized' ), + 'desc_tip' => _x( 'We recommend choosing the order status that you set when your products have been shipped.', 'trusted-shops', 'woocommerce-germanized' ), + 'default' => array( 'wc-completed' ), + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_review_reminder_status', + 'type' => 'multiselect', + 'class' => 'chosen_select', + ), + + array( + 'title' => _x( 'Days until Review Request', 'trusted-shops', 'woocommerce-germanized' ), + 'desc_tip' => _x( 'Set the number of days to wait after an order has reached the order status you selected above before having a review request sent to your customers.', 'trusted-shops', 'woocommerce-germanized' ), + 'default' => 7, + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_review_reminder_days', + 'type' => 'number', + 'custom_attributes' => array( + 'step' => '1', + 'min' => 0, + 'data-validate' => 'integer', + ), + ), + + array( + 'title' => _x( 'Permission via checkbox', 'trusted-shops', 'woocommerce-germanized' ), + 'desc_tip' => _x( 'If the checkbox is activated, only customers who gave their consent will receive Review Requests.', 'trusted-shops', 'woocommerce-germanized' ), + 'default' => '', + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_review_reminder_checkbox', + 'type' => 'html', + 'html' => '' . _x( 'Edit checkbox', 'trusted-shops', 'woocommerce-germanized' ) . '', + ), + + array( + 'title' => _x( 'Unsubscribe via link', 'trusted-shops', 'woocommerce-germanized' ), + 'desc' => _x( 'Allows the customer to unsubscribe from Review Requests.', 'trusted-shops', 'woocommerce-germanized' ), + 'default' => 'yes', + 'id' => 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_review_reminder_opt_out', + 'type' => 'ts_toggle', + ), + + array( + 'type' => 'sectionend', + 'id' => 'trusted_shops_review_reminder_options', + ), + + ) + ); + } + + if ( ! empty( $defaults ) ) { + foreach ( $settings as $key => $setting ) { + if ( isset( $setting['id'] ) ) { + foreach ( $defaults as $setting_id => $default ) { + if ( $setting_id === $setting['id'] ) { + $settings[ $key ] = array_replace_recursive( $setting, $default ); + } + } + } + } + } + + return $settings; + } + + /** + * Get Trusted Shops related Settings for Admin Interface + * + * @return array + */ + public function get_settings() { + + $attributes = wc_get_attribute_taxonomies(); + $linked_attributes = array(); + + // Set attributes + foreach ( $attributes as $attribute ) { + $linked_attributes[ $attribute->attribute_name ] = $attribute->attribute_label; + } + + // Add empty option placeholder to allow clearing + $linked_attributes = array_merge( array( '' => '' ), $linked_attributes ); + + $update_settings = array( + 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_trustbadge_code' => array( + 'default' => $this->base->get_trustbadge_code( false ), + ), + 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_review_sticker_font' => array( + 'options' => $this->get_font_families(), + ), + 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_review_sticker_code' => array( + 'default' => $this->base->get_review_sticker_code( false ), + ), + 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_rich_snippets_code' => array( + 'default' => $this->base->get_rich_snippets_code( false ), + ), + 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_product_sticker_code' => array( + 'default' => $this->base->get_product_sticker_code( false ), + ), + 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_product_widget_code' => array( + 'default' => $this->base->get_product_widget_code( false ), + ), + 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_brand_attribute' => array( + 'options' => $linked_attributes, + ), + ); + + if ( $this->base->supports( 'reminder' ) ) { + $update_settings[ 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_review_reminder_status' ] = array( + 'options' => $this->get_order_statuses(), + ); + } + + $settings = $this->get_settings_array( $update_settings ); + + return $settings; + } + + public function get_image( $img ) { + $language = $this->base->get_language(); + $endings = array( '.jpg', '.png' ); + $last = substr( $img, -4 ); + $ending = ''; + + if ( in_array( $last, $endings, true ) ) { + $ending = $last; + $img = substr( $img, 0, -4 ); + } + + $new_img = $img . '_' . $language . $ending; + + return $this->base->plugin->plugin_url() . '/assets/images/ts/' . $new_img; + } + + public function get_sidebar() { + ob_start(); + ?> +
+
+
+

+ + +
+ +
+
+ + +
+
+ + +
+
+ +
+ +
+ +
+ + + + + +
+ +
+

Settings and deactivate "Collect reviews automatically"', 'trusted-shops', 'woocommerce-germanized' ); ?>

+ +
+ +
+

Shop Reviews > Review Collector', 'trusted-shops', 'woocommerce-germanized' ); ?>

+ +
+
+
+ base->option_prefix . 'trusted_shops_id' ] ) && $_POST[ 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_id' ] !== $this->base->id ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing + update_option( '_woocommerce_' . $this->base->option_prefix . 'trusted_shops_update_reviews', 1 ); + } + } + + public function after_save( $settings ) { + $this->base->refresh(); + + if ( get_option( 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_integration_mode' ) === 'standard' ) { + // Delete code snippets + delete_option( 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_trustbadge_code' ); + delete_option( 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_product_sticker_code' ); + delete_option( 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_product_widget_code' ); + delete_option( 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_rich_snippets_code' ); + delete_option( 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_review_sticker_code' ); + update_option( 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_product_widget_selector', '#ts_product_widget' ); + update_option( 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_product_sticker_selector', '#ts_product_sticker' ); + } + + // Disable Reviews if Trusted Shops review collection has been enabled + if ( get_option( 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_reviews_enable' ) === 'yes' ) { + update_option( 'woocommerce_enable_review_rating', 'no' ); + } + + if ( get_option( '_woocommerce_' . $this->base->option_prefix . 'trusted_shops_update_reviews' ) ) { + $this->base->get_dependency( 'schedule' )->update_reviews(); + } + + delete_option( '_woocommerce_' . $this->base->option_prefix . 'trusted_shops_update_reviews' ); + } + + public function review_collector_export_csv() { + if ( ! current_user_can( 'manage_woocommerce' ) ) { + return; + } + + if ( ! isset( $_GET['action'] ) || 'wc_' . $this->base->option_prefix . 'trusted-shops-export' !== $_GET['action'] || ( isset( $_GET['action'], $_REQUEST['_wpnonce'] ) && 'wc_' . $this->base->option_prefix . 'trusted-shops-export' === $_GET['action'] && ! wp_verify_nonce( wp_unslash( $_REQUEST['_wpnonce'] ), 'wc_' . $this->base->option_prefix . 'trusted-shops-export' ) ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + return; + } + + $interval_d = ( ( isset( $_GET['interval'] ) && ! empty( $_GET['interval'] ) ) ? absint( $_GET['interval'] ) : 30 ); + $days_to_send = ( ( isset( $_GET['days'] ) && ! empty( $_GET['days'] ) ) ? absint( $_GET['days'] ) : 5 ); + $status = ( ( isset( $_GET['status'] ) && ! empty( $_GET['status'] ) ) ? wc_clean( wp_unslash( $_GET['status'] ) ) : '' ); + + update_option( 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_review_collector_days_to_send', $days_to_send ); + update_option( 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_review_collector', $interval_d ); + + if ( wc_ts_woocommerce_supports_crud() ) { + include_once 'class-wc-trusted-shops-review-exporter.php'; + + $exporter = new WC_Trusted_Shops_Review_Exporter(); + $exporter->set_days_until_send( $days_to_send ); + $exporter->set_interval_days( $interval_d ); + + if ( ! empty( $status ) ) { + $exporter->set_statuses( array( $status ) ); + } + + if ( isset( $_GET['lang'] ) && ! empty( $_GET['lang'] ) ) { + $exporter->set_lang( wc_clean( wp_unslash( $_GET['lang'] ) ) ); + } + + $exporter->export(); + } + } + + public function review_collector_export() { + + $href_org = admin_url(); + $href_org = add_query_arg( + array( + 'action' => 'wc_' . $this->base->option_prefix . 'trusted-shops-export', + '_wpnonce' => wp_create_nonce( 'wc_' . $this->base->option_prefix . 'trusted-shops-export' ), + 'lang' => $this->base->is_multi_language_setup() ? $this->base->get_multi_language_compatibility()->get_current_language() : '', + ), + $href_org + ); + + if ( ! wc_ts_woocommerce_supports_crud() ) { + return; + } + + $days_interval = get_option( 'woocommerce_gzd_trusted_shops_review_collector', 30 ); + $days_to_send = get_option( 'woocommerce_gzd_trusted_shops_review_collector_days_to_send', 5 ); + ?> +

+
+

get_trusted_url( 'https://www.trustedshops.com/tsb2b/sa/ratings/reviewCollector/reviewCollector.seam' ) ) . '" target="_blank">' . esc_html_x( 'My Trusted Shops account', 'trusted-shops', 'woocommerce-germanized' ) . '' ) ); ?>

+
+ + + + + + + +
+ + + + get_trusted_url( 'https://www.trustedshops.com/tsb2b/sa/ratings/reviewCollector/reviewCollector.seam' ) ) . '" target="_blank">' . esc_html_x( 'here', 'trusted-shops', 'woocommerce-germanized' ) . '' ) ); ?> +
+
+ + +
+
+ +
+
+
+ false, + ) + ); + + $url = empty( $url ) ? $this->base->signup_url : $url; + + return $this->get_trusted_url( $url, $args ); + } + + public function get_trusted_url( $url, $args = array() ) { + $param_args = $this->base->et_params; + $args = wp_parse_args( + $args, + array( + 'utm_term' => substr( get_locale(), 0, 2 ), + 'shop_id' => $this->base->ID, + 'params' => false, + 'lang_mapping' => array(), + ) + ); + + $current_lang = $this->base->get_language(); + + $base_lang = isset( $args['lang_mapping']['en'] ) ? $args['lang_mapping']['en'] : 'en'; + $current_lang = isset( $args['lang_mapping'][ $current_lang ] ) ? $args['lang_mapping'][ $current_lang ] : $current_lang; + $url = str_replace( "/{$base_lang}/", '/' . $current_lang . '/', $url ); + + if ( 'gzd_' === $this->base->option_prefix && substr( $url, -11 ) === 'woocommerce' ) { + $url = str_replace( 'woocommerce', 'woocommerce_germanized', $url ); + } + + if ( $args['params'] ) { + $param_args = array_replace_recursive( + $param_args, + array( + 'utm_term' => $args['utm_term'], + 'shop_id' => $args['shop_id'], + ) + ); + + return esc_url_raw( add_query_arg( $param_args, $url ) ); + } else { + return $url; + } + } + +} diff --git a/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-core.php b/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-core.php new file mode 100644 index 000000000..82b8e209e --- /dev/null +++ b/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-core.php @@ -0,0 +1,471 @@ +version = Package::get_version(); + + // Define constants + $this->define_constants(); + + // Include required files + $this->includes(); + $this->setup_compatibility(); + + // Hooks + add_filter( 'plugin_action_links_' . plugin_basename( WC_TRUSTED_SHOPS_PLUGIN_FILE ), array( $this, 'action_links' ) ); + add_action( 'init', array( $this, 'init' ), 1 ); + add_filter( 'woocommerce_locate_template', array( $this, 'filter_templates' ), 0, 3 ); + + // Initialize Trusted Shops module + $this->trusted_shops = new WC_Trusted_Shops( + $this, + array( + 'supports' => Package::is_integration() ? array( 'reminder' ) : array(), + 'prefix' => Package::is_integration() ? 'GZD_' : '', + 'signup_url' => 'http://www.trustbadge.com/de/Preise/', + 'path' => WC_TRUSTED_SHOPS_ABSPATH . 'includes/', + ) + ); + + // Loaded action + do_action( 'woocommerce_trusted_shops_loaded' ); + } + + /** + * Init Trusted Shops when WordPress initializes. + */ + public function init() { + // Before init action + do_action( 'before_woocommerce_trusted_shops_init' ); + + if ( ! Package::is_integration() ) { + $this->load_plugin_textdomain(); + add_filter( 'woocommerce_get_settings_pages', array( $this, 'add_settings' ) ); + } else { + add_filter( 'woocommerce_email_classes', array( $this, 'add_emails' ), 10 ); + add_filter( 'woocommerce_gzd_wpml_email_ids', array( $this, 'add_wpml_emails' ), 10 ); + add_filter( 'woocommerce_gzd_admin_settings_tabs', array( $this, 'add_germanized_settings_tab' ), 10, 1 ); + } + + add_action( 'admin_enqueue_scripts', array( $this, 'add_admin_styles' ) ); + add_filter( 'admin_footer_text', array( $this, 'admin_footer_text' ), 15 ); + add_action( 'admin_print_styles', array( $this, 'add_notices' ), 1 ); + + // Change email template path if is germanized email template + add_filter( 'woocommerce_template_directory', array( $this, 'set_woocommerce_template_dir' ), 10, 2 ); + add_filter( 'woocommerce_locate_core_template', array( $this, 'set_woocommerce_core_template_dir' ), 10, 3 ); + + add_action( 'woocommerce_admin_field_ts_toggle', array( $this, 'toggle_input' ), 10 ); + add_filter( 'woocommerce_admin_settings_sanitize_option', array( $this, 'save_toggle_input_field' ), 0, 3 ); + + // Init action + do_action( 'woocommerce_trusted_shops_init' ); + } + + public function add_germanized_settings_tab( $tabs ) { + include_once dirname( __FILE__ ) . '/admin/settings/class-wc-ts-gzd-settings-tab.php'; + $tabs['trusted_shops'] = 'WC_TS_GZD_Settings_Tab'; + return $tabs; + } + + /** + * Add notices + styles if needed. + */ + public function add_notices() { + $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : false; + $screen_id = $screen ? $screen->id : ''; + $show_on_screens = array( + 'dashboard', + 'plugins', + ); + + $wc_screen_ids = function_exists( 'wc_get_screen_ids' ) ? wc_get_screen_ids() : array(); + + // Notices should only show on WooCommerce screens, the main dashboard, and on the plugins screen. + if ( ! in_array( $screen_id, $wc_screen_ids, true ) && ! in_array( $screen_id, $show_on_screens, true ) ) { + return; + } + + if ( 1 === (int) get_option( '_wc_ts_needs_update' ) ) { + if ( current_user_can( 'manage_woocommerce' ) ) { + wp_enqueue_style( 'woocommerce-activation', plugins_url( '/assets/css/activation.css', WC_PLUGIN_FILE ), array(), WC_TRUSTED_SHOPS_VERSION ); + wp_enqueue_style( 'woocommerce-ts-activation', plugins_url( '/assets/css/activation.css', WC_TRUSTED_SHOPS_PLUGIN_FILE ), array(), WC_TRUSTED_SHOPS_VERSION ); + + add_action( 'admin_notices', array( $this, 'install_notice' ) ); + } + } + } + + /** + * Show the install notices + */ + public function install_notice() { + + // If we need to update, include a message with the update button + if ( 1 === (int) get_option( '_wc_ts_needs_update' ) ) { + include WC_TRUSTED_SHOPS_ABSPATH . 'includes/admin/views/html-notice-update.php'; + } + } + + public function toggle_input( $value ) { + // Custom attribute handling. + $custom_attributes = array(); + + if ( ! empty( $value['custom_attributes'] ) && is_array( $value['custom_attributes'] ) ) { + foreach ( $value['custom_attributes'] as $attribute => $attribute_value ) { + $custom_attributes[] = esc_attr( $attribute ) . '="' . esc_attr( $attribute_value ) . '"'; + } + } + + // Description handling. + $field_description = WC_Admin_Settings::get_field_description( $value ); + $description = $field_description['description']; + $tooltip_html = $field_description['tooltip_html']; + $option_value = WC_Admin_Settings::get_option( $value['id'], $value['default'] ); + ?> + + + + + + + + + + /> + + + plugin_path() . '/templates/' . $template ) ) { + $core_file = $this->plugin_path() . '/templates/' . $template; + } + + return $core_file; + } + + public function set_woocommerce_template_dir( $dir, $template ) { + if ( file_exists( WC_trusted_shops()->plugin_path() . '/templates/' . $template ) ) { + return 'woocommerce-trusted-shops'; + } + + return $dir; + } + + public function admin_footer_text( $footer_text ) { + if ( ! current_user_can( 'manage_woocommerce' ) ) { + return; + } + + // Check to make sure we're on a WooCommerce admin page + if ( isset( $_GET['tab'] ) && 'trusted-shops' === $_GET['tab'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $footer_text = wp_kses_post( sprintf( _x( 'If the App helped you, please leave a %1$s★★★★★%2$s in the WordPress plugin repository.', 'trusted-shops', 'woocommerce-germanized' ), '', '' ) ); + } + + return $footer_text; + } + + /** + * Auto-load WC_Trusted_Shops classes on demand to reduce memory consumption. + * + * @param mixed $class + * @return void + */ + public function autoload( $class ) { + $class = strtolower( $class ); + $path = $this->plugin_path() . '/includes/'; + + if ( 0 !== strpos( $class, 'wc_ts_' ) && 0 !== strpos( $class, 'wc_trusted_shops' ) ) { + return; + } + + $file = 'class-' . str_replace( '_', '-', $class ) . '.php'; + + if ( strpos( $class, 'wc_ts_compatibility' ) !== false ) { + $path = $this->plugin_path() . '/includes/compatibility/'; + } + + if ( $path && is_readable( $path . $file ) ) { + include_once $path . $file; + return; + } + } + + /** + * Get the plugin url. + * + * @return string + */ + public function plugin_url() { + return Package::get_url(); + } + + /** + * Get the plugin path. + * + * @return string + */ + public function plugin_path() { + return untrailingslashit( Package::get_path() ); + } + + /** + * Get the language path + * + * @return string + */ + public function language_path() { + return $this->plugin_path() . '/i18n/languages'; + } + + /** + * Define WC_Germanized Constants + */ + private function define_constants() { + define( 'WC_TRUSTED_SHOPS_PLUGIN_FILE', trailingslashit( Package::get_path() ) . 'woocommerce-trusted-shops.php' ); + define( 'WC_TRUSTED_SHOPS_ABSPATH', trailingslashit( Package::get_path() ) ); + define( 'WC_TRUSTED_SHOPS_VERSION', $this->version ); + } + + public function setup_compatibility() { + $plugins = apply_filters( + 'woocommerce_ts_compatibilities', + array( + 'wpml-string-translation', + ) + ); + foreach ( $plugins as $comp ) { + $classname = str_replace( ' ', '_', 'WC_TS_Compatibility_' . ucwords( str_replace( '-', ' ', $comp ) ) ); + if ( class_exists( $classname ) ) { + $this->compatibilities[ $comp ] = new $classname(); + } + } + } + + public function get_compatibility( $name ) { + return ( isset( $this->compatibilities[ $name ] ) ? $this->compatibilities[ $name ] : false ); + } + + /** + * Include required core files used in admin and on the frontend. + */ + private function includes() { + include_once WC_TRUSTED_SHOPS_ABSPATH . 'includes/abstracts/abstract-wc-ts-compatibility.php'; + include_once WC_TRUSTED_SHOPS_ABSPATH . 'includes/class-wc-ts-install.php'; + } + + /** + * Filter WooCommerce Templates to look into /templates before looking within theme folder + * + * @param string $template + * @param string $template_name + * @param string $template_path + * @return string + */ + public function filter_templates( $template, $template_name, $template_path ) { + if ( ! $template_path ) { + $template_path = WC()->template_path(); + } + + // Make filter gzd_compatible + $template_name = apply_filters( 'woocommerce_trusted_shops_template_name', $template_name ); + + // Check Theme + $theme_template = locate_template( + array( + trailingslashit( $template_path ) . $template_name, + $template_name, + ) + ); + + // Load Default + if ( ! $theme_template ) { + if ( file_exists( $this->plugin_path() . '/templates/' . $template_name ) ) { + $template = $this->plugin_path() . '/templates/' . $template_name; + } + } else { + $template = $theme_template; + } + + return apply_filters( 'woocommerce_trusted_shops_filter_template', $template, $template_name, $template_path ); + } + + /** + * Load Localisation files for WooCommerce Germanized. + */ + public function load_plugin_textdomain() { + $locale = is_admin() && function_exists( 'get_user_locale' ) ? get_user_locale() : get_locale(); + $locale = apply_filters( 'plugin_locale', $locale, 'woocommerce-germanized' ); + unload_textdomain( 'woocommerce-trusted-shops' ); + load_textdomain( 'woocommerce-trusted-shops', trailingslashit( WP_LANG_DIR ) . 'woocommerce-trusted-shops/woocommerce-trusted-shops-' . $locale . '.mo' ); + load_plugin_textdomain( 'woocommerce-trusted-shops', false, plugin_basename( dirname( __FILE__ ) ) . '/i18n/languages/' ); + } + + /** + * Show action links on the plugin screen + * + * @param mixed $links + * @return array + */ + public function action_links( $links ) { + return array_merge( + array( + '' . _x( 'Settings', 'trusted-shops', 'woocommerce-germanized' ) . '', + ), + $links + ); + } + + /** + * Add custom styles to Admin + */ + public function add_admin_styles() { + $screen = get_current_screen(); + + if ( isset( $_GET['tab'] ) && 'trusted-shops' === $_GET['tab'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + do_action( 'woocommerce_trusted_shops_load_admin_scripts' ); + } + } + + /** + * Add WooCommerce Germanized Settings Tab + * + * @param array $integrations + * @return array + */ + public function add_settings( $integrations ) { + $integrations[] = new WC_TS_Settings_Handler(); + + return $integrations; + } + + /** + * Add Custom Email templates + * + * @param array $mails + * @return array + */ + public function add_emails( $mails ) { + $mails['WC_TS_Email_Customer_Trusted_Shops'] = include_once $this->plugin_path() . '/includes/emails/class-wc-ts-email-customer-trusted-shops.php'; + + return $mails; + } + + public function add_wpml_emails( $mails ) { + $mails['WC_TS_Email_Customer_Trusted_Shops'] = 'customer_trusted_shops'; + + return $mails; + } + } + +endif; + +/** + * Returns the global instance of WooCommerce Germanized + */ +function WC_trusted_shops() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionNameInvalid + return WooCommerce_Trusted_Shops::instance(); +} + +$GLOBALS['woocommerce_trusted_shops'] = WC_trusted_shops(); diff --git a/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-review-exporter.php b/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-review-exporter.php new file mode 100644 index 000000000..358958b81 --- /dev/null +++ b/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-review-exporter.php @@ -0,0 +1,171 @@ +statuses = array_keys( wc_get_order_statuses() ); + $this->column_names = $this->get_default_column_names(); + } + + /** + * Return an array of columns to export. + * + * @since 3.1.0 + * @return array + */ + public function get_default_column_names() { + return apply_filters( + "woocommerce_gzd_{$this->export_type}_default_columns", + array( + 'id' => 'reference', + 'date' => 'date', + 'days' => 'days', + 'billing_email' => 'email', + 'billing_first_name' => 'firstName', + 'billing_last_name' => 'lastName', + ) + ); + } + + public function get_interval_days() { + return absint( $this->days_interval ); + } + + public function set_interval_days( $days ) { + $this->days_interval = absint( $days ); + } + + public function get_days_until_send() { + return $this->days_to_send; + } + + public function set_days_until_send( $days ) { + $this->days_to_send = absint( $days ); + } + + public function get_statuses() { + return $this->statuses; + } + + public function set_statuses( $statuses ) { + $this->statuses = (array) $statuses; + } + + public function set_lang( $lang ) { + $this->lang = $lang; + } + + public function get_lang() { + return $this->lang; + } + + /** + * Prepare data that will be exported. + */ + public function prepare_data_to_export() { + $columns = $this->get_column_names(); + $date = date( 'Y-m-d', strtotime( '-' . $this->get_interval_days() . ' days' ) ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date + $args = array( + 'post_type' => 'shop_order', + 'post_status' => $this->get_statuses(), + 'showposts' => -1, + 'date_query' => array( + array( + 'after' => $date, + ), + ), + ); + + if ( $this->get_lang() !== '' && 'all' !== $this->get_lang() ) { + $args['meta_query'] = array(); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query + $args['meta_query']['wpml'] = array( + 'key' => 'wpml_language', + 'compare' => '=', + 'value' => $this->get_lang(), + ); + } + + $order_query = new WP_Query( apply_filters( "woocommerce_gzd_{$this->export_type}_query_args", $args ) ); + $this->total_rows = $order_query->found_posts; + $this->row_data = array(); + + while ( $order_query->have_posts() ) { + $order_query->next_post(); + + $order = wc_get_order( $order_query->post->ID ); + $row = array(); + + foreach ( $columns as $column_id => $column_name ) { + $column_id = strstr( $column_id, ':' ) ? current( explode( ':', $column_id ) ) : $column_id; + $value = ''; + + if ( is_callable( array( $this, "get_column_value_{$column_id}" ) ) ) { + // Handle special columns which don't map 1:1 to order data. + $value = $this->{"get_column_value_{$column_id}"}( $order ); + + } elseif ( wc_ts_get_crud_data( $order, $column_id ) ) { + // Default and custom handling. + $value = wc_ts_get_crud_data( $order, $column_id ); + } + + $row[ $column_id ] = $value; + } + + $this->row_data[] = apply_filters( 'woocommerce_gzd_trusted_shops_review_export_row_data', $row, $order ); + } + } + + public function get_column_value_date( $order ) { + return wc_ts_get_order_date( $order, 'd.m.Y' ); + } + + public function get_column_value_days( $order ) { + return $this->get_days_until_send(); + } +} diff --git a/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-schedule.php b/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-schedule.php new file mode 100644 index 000000000..804e764c0 --- /dev/null +++ b/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-schedule.php @@ -0,0 +1,246 @@ +base = $base; + + add_action( 'woocommerce_gzd_trusted_shops_reviews', array( $this, 'update_reviews' ) ); + add_action( 'admin_init', array( $this, 'update_default_reviews' ), 10 ); + add_action( 'woocommerce_gzd_trusted_shops_reviews', array( $this, 'send_mails' ) ); + } + + public function update_default_reviews() { + // Generate reviews for the first time + $option_key = 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_reviews_cache'; + + $section = isset( $_GET['section'] ) ? wc_clean( wp_unslash( $_GET['section'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended + + // Do only update default reviews if the admin user open the settings page. + if ( 'trusted_shops' !== $section ) { + return; + } + + if ( ! get_option( $option_key, false ) ) { + $this->update_reviews_inner(); + } + + if ( $this->base->is_multi_language_setup() ) { + $compatibility = $this->base->get_multi_language_compatibility(); + $current_language = $compatibility->get_current_language(); + + global $wc_ts_original_lang; + + $wc_ts_original_lang = $current_language; + + foreach ( $compatibility->get_languages() as $language ) { + + if ( $compatibility->get_default_language() === $language ) { + continue; + } + + $option_key .= '_' . $language; + + if ( ! get_option( $option_key, false ) ) { + $this->update_reviews_inner( $language ); + } + } + } + } + + /** + * Update Review Cache by grabbing information from xml file + */ + public function update_reviews() { + $this->update_reviews_inner(); + + if ( $this->base->is_multi_language_setup() ) { + + $compatibility = $this->base->get_multi_language_compatibility(); + $current_language = $compatibility->get_current_language(); + + global $wc_ts_original_lang; + + $wc_ts_original_lang = $current_language; + + foreach ( $compatibility->get_languages() as $language ) { + if ( $compatibility->get_default_language() === $language ) { + continue; + } + + $this->update_reviews_inner( $language ); + } + } + } + + protected function update_reviews_inner( $lang = '' ) { + if ( ! empty( $lang ) ) { + wc_ts_switch_language( $lang ); + } + + if ( ! $this->base->is_rich_snippets_enabled() ) { + if ( ! empty( $lang ) ) { + wc_ts_restore_language(); + } + + return; + } + + $update = array(); + + if ( $this->base->is_enabled() ) { + + $response = wp_remote_post( $this->base->api_url ); + + if ( is_array( $response ) ) { + $output = json_decode( $response['body'], true ); + + if ( isset( $output['response']['data'] ) ) { + $reviews = $output['response']['data']['shop']['qualityIndicators']['reviewIndicator']; + $update['count'] = (string) $reviews['activeReviewCount']; + $update['avg'] = (float) $reviews['overallMark']; + $update['max'] = '5.00'; + } + } + } + + $option_key = 'woocommerce_' . $this->base->option_prefix . 'trusted_shops_reviews_cache'; + + if ( ! empty( $lang ) ) { + $option_key .= '_' . $lang; + } + + update_option( $option_key, $update ); + + if ( ! empty( $lang ) ) { + wc_ts_restore_language(); + } + } + + /** + * Placeholder to avoid fatal errors within scheduled actions. + * + * @deprecated 2.2.5 + */ + public function update_review_widget() {} + + /** + * Send review reminder mails after x days + */ + public function send_mails() { + if ( $this->base->is_multi_language_setup() ) { + $compatibility = $this->base->get_multi_language_compatibility(); + $current_language = $compatibility->get_current_language(); + + global $wc_ts_original_lang; + + $wc_ts_original_lang = $current_language; + + foreach ( $compatibility->get_languages() as $language ) { + $this->send_mails_inner( $language ); + } + } else { + $this->send_mails_inner(); + } + } + + protected function send_mails_inner( $lang = '' ) { + if ( ! empty( $lang ) ) { + wc_ts_switch_language( $lang ); + } + + if ( ! $this->base->is_review_reminder_enabled() ) { + if ( ! empty( $lang ) ) { + wc_ts_restore_language(); + } + + return; + } + + $order_statuses = $this->base->review_reminder_status; + + if ( ! is_array( $order_statuses ) ) { + $order_statuses = array( $order_statuses ); + } + + $args = array( + 'post_type' => 'shop_order', + 'post_status' => apply_filters( 'woocommerce_trusted_shops_review_reminder_valid_order_statuses', $order_statuses ), + 'showposts' => -1, + 'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query + 'relation' => 'AND', + 'is_sent' => array( + 'key' => '_trusted_shops_review_mail_sent', + 'compare' => 'NOT EXISTS', + ), + 'opted_in' => array( + 'key' => '_ts_review_reminder_opted_in', + 'compare' => '=', + 'value' => 'yes', + ), + ), + ); + + if ( ! empty( $lang ) ) { + $args['meta_query']['wpml'] = array( + 'key' => 'wpml_language', + 'compare' => '=', + 'value' => $lang, + ); + } + + $order_query = new WP_Query( apply_filters( 'woocommerce_trusted_shops_review_reminder_order_args', $args, $lang ) ); + + while ( $order_query->have_posts() ) { + + $order_query->next_post(); + + if ( ! $order = wc_get_order( $order_query->post->ID ) ) { + continue; + } + + $completed_date = apply_filters( 'woocommerce_trusted_shops_review_reminder_order_completed_date', $order->get_date_completed(), $order ); + + if ( ! $completed_date ) { + continue; + } + + $now = new DateTime(); + $diff = $now->diff( $completed_date ); + $min_days = (int) $this->base->review_reminder_days; + + if ( $diff->days >= $min_days ) { + + if ( apply_filters( 'woocommerce_trusted_shops_send_review_reminder_email', true, $order ) ) { + + $mails = WC()->mailer()->get_emails(); + + foreach ( $mails as $mail ) { + + if ( 'customer_trusted_shops' === $mail->id ) { + $mail->trigger( wc_ts_get_crud_data( $order, 'id' ) ); + + update_post_meta( wc_ts_get_crud_data( $order, 'id' ), '_trusted_shops_review_mail_sent', 1 ); + } + } + } + } + } + + if ( ! empty( $lang ) ) { + wc_ts_restore_language(); + } + } +} diff --git a/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-shortcodes.php b/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-shortcodes.php new file mode 100644 index 000000000..0299f9331 --- /dev/null +++ b/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-shortcodes.php @@ -0,0 +1,99 @@ +base = $base; + + add_action( 'init', array( $this, 'init' ), 3 ); + } + + public function init() { + + // Define shortcodes + $shortcodes = array( + 'trusted_shops_rich_snippets' => array( $this, 'trusted_shops_rich_snippets' ), + 'trusted_shops_review_sticker' => array( $this, 'trusted_shops_review_sticker' ), + 'trusted_shops_badge' => array( $this, 'trusted_shops_badge' ), + ); + + foreach ( $shortcodes as $shortcode => $function ) { + add_shortcode( apply_filters( "{$shortcode}_shortcode_tag", $shortcode ), $function ); + } + + } + + /** + * Returns Trusted Shops rich snippet review html + * + * @param array $atts + * @return string + */ + public function trusted_shops_rich_snippets( $atts ) { + ob_start(); + wc_get_template( + 'trusted-shops/rich-snippets.php', + array( + 'plugin' => $this->base, + ) + ); + $html = ob_get_clean(); + + return $this->base->is_enabled() ? $html : ''; + } + + /** + * Returns Trusted Shops reviews graphic + * + * @param array $atts + * @return string + */ + public function trusted_shops_review_sticker( $atts ) { + $atts = wp_parse_args( + $atts, + array( + 'element' => '#ts_review_sticker', + ) + ); + + ob_start(); + wc_get_template( + 'trusted-shops/review-sticker.php', + array( + 'plugin' => $this->base, + 'element' => $atts['element'], + ) + ); + $html = ob_get_clean(); + return $this->base->is_enabled() ? '
' . $html . '
' : ''; + } + + /** + * Returns Trusted Shops Badge html + * + * @param array $atts + * @return string + */ + public function trusted_shops_badge( $atts ) { + $atts = wp_parse_args( + $atts, + array( + 'width' => 0, + ) + ); + + return $this->base->is_enabled() ? '' : ''; + } + +} diff --git a/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-template-hooks.php b/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-template-hooks.php new file mode 100644 index 000000000..3932ae4e2 --- /dev/null +++ b/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-template-hooks.php @@ -0,0 +1,280 @@ +base = $base; + + // Load hooks on init so that language-specific settings are loaded + add_action( 'init', array( $this, 'init' ), 10 ); + + // Always register checkbox to avoid language problems + add_action( 'woocommerce_gzd_register_legal_core_checkboxes', array( $this, 'review_reminder_checkbox' ), 30 ); + } + + public function init() { + if ( $this->base->is_enabled() ) { + add_action( 'woocommerce_thankyou', array( $this, 'template_thankyou' ), 10, 1 ); + add_action( 'wp_footer', array( $this, 'template_trustbadge' ), 250 ); + } + + if ( $this->base->product_reviews_visible() ) { + add_filter( 'woocommerce_product_tabs', array( $this, 'remove_review_tab' ), 40, 1 ); + } + + if ( $this->base->is_product_sticker_enabled() ) { + add_filter( 'woocommerce_product_tabs', array( $this, 'review_tab' ), 50, 1 ); + } + + if ( $this->base->is_product_widget_enabled() ) { + add_filter( 'woocommerce_trusted_shops_template_name', array( $this, 'set_product_widget_template' ), 50, 1 ); + } + + if ( $this->base->is_rich_snippets_enabled() ) { + add_action( 'wp_footer', array( $this, 'insert_rich_snippets' ), 20 ); + } + + // Save Fields on order + if ( $this->base->is_review_reminder_enabled() ) { + add_action( 'woocommerce_checkout_update_order_meta', array( $this, 'update_order_meta' ) ); + + if ( 'yes' === $this->base->review_reminder_opt_out ) { + // Email notices right beneath order table + add_action( 'woocommerce_email_after_order_table', array( $this, 'email_cancel_review_reminder' ), 8, 3 ); + add_filter( 'woocommerce_email_styles', array( $this, 'email_styles' ) ); + + // Check for customer activation + add_action( 'template_redirect', array( $this, 'cancel_review_reminder_check' ) ); + } + } + } + + public function insert_rich_snippets() { + $insert = false; + + if ( in_array( 'category', $this->base->get_rich_snippets_locations(), true ) ) { + if ( is_product_category() ) { + $insert = true; + } + } + + if ( in_array( 'home', $this->base->get_rich_snippets_locations(), true ) ) { + if ( function_exists( 'is_shop' ) && is_shop() ) { + $insert = true; + } + } + + if ( in_array( 'product', $this->base->get_rich_snippets_locations(), true ) ) { + if ( is_product() ) { + $insert = true; + } + } + + if ( $insert ) { + echo do_shortcode( '[trusted_shops_rich_snippets]' ); + } + } + + public function cancel_review_reminder_check() { + if ( isset( $_GET['disable-review-reminder'] ) && isset( $_GET['order-id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + + $order_id = absint( $_GET['order-id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $code = wc_clean( wp_unslash( $_GET['disable-review-reminder'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended + + if ( ! empty( $code ) && ! empty( $order_id ) ) { + + $order_query = new WP_Query( + array( + 'post_type' => 'shop_order', + 'p' => $order_id, + 'post_status' => array_keys( wc_get_order_statuses() ), + 'posts_per_page' => 1, + 'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query + 'code' => array( + 'key' => '_ts_cancel_review_reminder_code', + 'compare' => '=', + 'value' => $code, + ), + ), + ) + ); + + while ( $order_query->have_posts() ) { + $order_query->next_post(); + $order = wc_get_order( $order_query->post->ID ); + + if ( $order ) { + $order_id = wc_ts_get_crud_data( $order, 'id' ); + + delete_post_meta( $order_id, '_ts_cancel_review_reminder_code' ); + delete_post_meta( $order_id, '_ts_review_reminder_opted_in' ); + + wp_die( wp_kses_post( sprintf( _x( 'Your review reminder e-mail has been cancelled successfully. Return to %s.', 'trusted-shops', 'woocommerce-germanized' ), '' . esc_html_x( 'Home', 'trusted-shops', 'woocommerce-germanized' ) . '' ) ) ); + } + } + } + } + } + + public function email_styles( $css ) { + $css .= ' + .wc-ts-cancel-review-reminder { + margin-top: 16px; + } + '; + + return $css; + } + + public function get_cancel_review_reminder_link( $order ) { + $code = wc_ts_get_crud_data( $order, 'ts_cancel_review_reminder_code' ); + + if ( ! $code || empty( $code ) ) { + global $wp_hasher; + + if ( empty( $wp_hasher ) ) { + require_once ABSPATH . WPINC . '/class-phpass.php'; + $wp_hasher = new PasswordHash( 8, true ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited + } + + $code = $wp_hasher->HashPassword( wp_generate_password( 20 ) ); + + update_post_meta( wc_ts_get_crud_data( $order, 'id' ), '_ts_cancel_review_reminder_code', $code ); + } + + $order_id = wc_ts_get_crud_data( $order, 'id' ); + $link = add_query_arg( + array( + 'disable-review-reminder' => $code, + 'order-id' => $order_id, + ), + get_site_url() + ); + + if ( $lang = wc_ts_get_order_language( $order ) ) { + $link = add_query_arg( array( 'lang' => $lang ), $link ); + } + + return esc_url_raw( apply_filters( 'woocommerce_trusted_shops_cancel_review_reminder_link', $link, $code, $order ) ); + } + + public function email_cancel_review_reminder( $order, $sent_to_admin, $plain_text ) { + $type = WC_germanized()->emails->get_current_email_object(); + + // Try to flush the cache before continuing + WC_GZD_Cache_Helper::maybe_flush_cache( + 'db', + array( + 'cache_type' => 'meta', + 'meta_type' => 'post', + 'meta_key' => 'ts_review_reminder_opted_in', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key + ) + ); + $opted_in = wc_ts_get_crud_data( $order, 'ts_review_reminder_opted_in' ); + + if ( $type && 'yes' === $opted_in && 'customer_processing_order' === $type->id ) { + wc_get_template( 'emails/cancel-review-reminder.php', array( 'link' => $this->get_cancel_review_reminder_link( $order ) ) ); + } + } + + public function update_order_meta( $order_id ) { + $checkbox = wc_gzd_get_legal_checkbox( 'review_reminder' ); + + if ( isset( $_POST['review_reminder'] ) || ! $checkbox || ( $checkbox && ! $checkbox->is_enabled() ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing + update_post_meta( $order_id, '_ts_review_reminder_opted_in', 'yes' ); + } + } + + public function review_reminder_checkbox() { + if ( ! function_exists( 'wc_gzd_register_legal_checkbox' ) ) { + return; + } + + wc_gzd_register_legal_checkbox( + 'review_reminder', + array( + 'html_id' => 'review-reminder', + 'html_name' => 'review_reminder', + 'html_wrapper_classes' => array( 'legal' ), + 'label' => _x( 'Yes, I would like to be reminded via e-mail after {days} day(s) to review my order. I am able to cancel the reminder at any time by clicking on the "cancel review reminder" link within the order confirmation.', 'trusted-shops', 'woocommerce-germanized' ), + 'label_args' => array( '{days}' => $this->base->review_reminder_days ), + 'hide_input' => false, + 'is_enabled' => false, + 'is_mandatory' => false, + 'error_message' => _x( 'Please allow us to send a review reminder by e-mail.', 'trusted-shops', 'woocommerce-germanized' ), + 'priority' => 6, + 'is_core' => true, + 'admin_name' => _x( 'Review reminder', 'trusted-shops', 'woocommerce-germanized' ), + 'admin_desc' => _x( 'Asks the customer to receive a Trusted Shops review reminder.', 'trusted-shops', 'woocommerce-germanized' ), + 'locations' => array( 'checkout' ), + ) + ); + } + + public function set_product_widget_template( $template ) { + + if ( in_array( $template, array( 'single-product/rating.php' ), true ) ) { + $template = 'trusted-shops/product-widget.php'; + } + + return $template; + } + + public function remove_review_tab( $tabs ) { + if ( isset( $tabs['reviews'] ) ) { + unset( $tabs['reviews'] ); + } + + return $tabs; + } + + public function review_tab( $tabs ) { + $tabs['trusted_shops_reviews'] = array( + 'title' => $this->base->product_sticker_tab_text, + 'priority' => 30, + 'callback' => array( $this, 'template_product_sticker' ), + ); + return $tabs; + } + + public function template_review_sticker( $template ) { + wc_get_template( + 'trusted-shops/review-sticker.php', + array( + 'plugin' => $this->base, + 'element' => '#ts_review_sticker', + ) + ); + } + + public function template_product_sticker( $template ) { + wc_get_template( 'trusted-shops/product-sticker.php', array( 'plugin' => $this->base ) ); + } + + public function template_trustbadge() { + wc_get_template( 'trusted-shops/trustbadge.php', array( 'plugin' => $this->base ) ); + } + + public function template_thankyou( $order_id ) { + wc_get_template( + 'trusted-shops/thankyou.php', + array( + 'order_id' => $order_id, + 'plugin' => $this->base, + ) + ); + } + +} diff --git a/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-widgets.php b/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-widgets.php new file mode 100644 index 000000000..107121ed3 --- /dev/null +++ b/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-widgets.php @@ -0,0 +1,34 @@ +base = $base; + + add_action( 'widgets_init', array( $this, 'include_widgets' ), 25 ); + } + + public function include_widgets() { + if ( $this->base->is_review_sticker_enabled() ) { + $this->register_widget( 'review_sticker' ); + } + } + + private function register_widget( $name ) { + $classname = $this->base->get_dependency_name( 'widget_' . $name ); + include_once 'widgets/class-' . strtolower( str_replace( '_', '-', $classname ) ) . '.php'; + register_widget( $classname ); + } + +} diff --git a/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops.php b/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops.php new file mode 100644 index 000000000..9be75601a --- /dev/null +++ b/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops.php @@ -0,0 +1,689 @@ +plugin = $plugin; + + $args = wp_parse_args( + $params, + array( + 'et_params' => array(), + 'signup_params' => array(), + 'prefix' => '', + 'signup_url' => '', + 'supports' => array( 'reminder' ), + 'path' => dirname( __FILE__ ) . '/', + ) + ); + + foreach ( $args as $arg => $val ) { + $this->$arg = $val; + } + + $this->option_prefix = strtolower( $this->prefix ); + $this->load(); + } + + public function load() { + + // Refresh TS ID + API URL + $this->refresh(); + $this->includes(); + + add_action( 'init', array( $this, 'refresh' ), 50 ); + + if ( is_admin() ) { + $this->get_dependency( 'admin' ); + } + + $this->get_dependency( 'schedule' ); + $this->get_dependency( 'shortcodes' ); + $this->get_dependency( 'widgets' ); + $this->get_dependency( 'template_hooks' ); + + if ( $this->is_enabled() ) { + add_action( 'wp_enqueue_scripts', array( $this, 'load_frontend_assets' ), 50 ); + + if ( is_admin() ) { + add_filter( 'woocommerce_gzd_wpml_translatable_options', array( $this, 'register_wpml_options' ), 20, 1 ); + add_filter( 'woocommerce_gzd_wpml_remove_translation_empty_equal', array( $this, 'stop_wpml_options_string_deletions' ), 20, 4 ); + } + } + } + + public function register_wpml_options( $settings ) { + $admin = $this->get_dependency( 'admin' ); + + return array_merge( $settings, $admin->get_translatable_settings() ); + } + + /** + * Make sure that other languages are not synced with main language e.g. option does not default to main language + * + * @param $allow + * @param $option + * @param $new_value + * @param $old_value + * @return bool + */ + public function stop_wpml_options_string_deletions( $allow, $option, $new_value, $old_value ) { + $admin = $this->get_dependency( 'admin' ); + + if ( array_key_exists( $option, $admin->get_translatable_settings() ) ) { + $allow = false; + } + + return $allow; + } + + public function includes() { + include_once $this->path . 'wc-ts-core-functions.php'; + } + + public function load_frontend_assets() { + $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; + $assets_path = $this->plugin->plugin_url() . '/assets/css'; + + wp_register_style( 'woocommerce-trusted-shops', $assets_path . '/layout' . $suffix . '.css', false, $this->plugin->version ); + wp_enqueue_style( 'woocommerce-trusted-shops' ); + } + + public function get_dependency_name( $name ) { + $classname = 'WC_Trusted_Shops_' . ucwords( str_replace( '-', '_', strtolower( $name ) ) ); + return $classname; + } + + public function get_dependency( $name ) { + $classname = $this->get_dependency_name( $name ); + + return call_user_func_array( array( $classname, 'instance' ), array( $this ) ); + } + + public function refresh() { + $this->id = $this->__get( 'id' ); + $this->api_url = 'http://api.trustedshops.com/rest/public/v2/shops/' . $this->id . '/quality.json'; + } + + public function get_multi_language_compatibility() { + return apply_filters( 'woocommerce_trusted_shops_multi_language_compatibility', $this->plugin->get_compatibility( 'wpml-string-translation' ) ); + } + + public function is_multi_language_setup() { + $compatibility = $this->get_multi_language_compatibility(); + + return $compatibility->is_activated() ? true : false; + } + + /** + * Get Trusted Shops Options + * + * @param string $key + * @return mixed + */ + public function __get( $key ) { + $option_name = 'woocommerce_' . $this->option_prefix . 'trusted_shops_' . $key; + $value = get_option( $option_name ); + + /** + * By default WPML does not allow empty strings to override default translations. + * This snippet manually checks for translations and allows to override default WPML translations. + */ + if ( ! is_admin() && $this->is_multi_language_setup() ) { + $compatibility = $this->get_multi_language_compatibility(); + + $default_language = $compatibility->get_default_language(); + $current_language = $compatibility->get_current_language(); + + if ( $current_language !== $default_language ) { + if ( isset( $this->options[ $current_language ][ $key ] ) ) { + return $this->options[ $current_language ][ $key ]; + } else { + if ( $string_id = $compatibility->get_string_id( $option_name ) ) { + $translation = $compatibility->get_string_translation( $string_id, $current_language ); + + if ( false !== $translation ) { + $this->options[ $current_language ][ $key ] = $translation; + $value = $translation; + } + } + } + } + } + + return $value; + } + + /** + * Checks whether a certain Trusted Shops Option isset + * + * @param string $key + * @return boolean + */ + public function __isset( $key ) { + return ( ! get_option( 'woocommerce_' . $this->option_prefix . 'trusted_shops_' . $key ) ) ? false : true; + } + + /** + * Checks whether Trusted Shops is enabled + * + * @return boolean + */ + public function is_enabled() { + return ( $this->id ) ? true : false; + } + + public function get_rich_snippets_locations() { + $locations = array(); + + if ( 'yes' === $this->rich_snippets_category ) { + $locations[] = 'category'; + } + + if ( 'yes' === $this->rich_snippets_product ) { + $locations[] = 'product'; + } + + if ( 'yes' === $this->rich_snippets_home ) { + $locations[] = 'home'; + } + + return $locations; + } + + public function is_trustbadge_enabled() { + return ( 'yes' === $this->trustbadge_enable && '' !== $this->id ? true : false ); + } + + /** + * Checks whether Trusted Shops Rich Snippets are enabled + * + * @return boolean + */ + public function is_rich_snippets_enabled() { + return ( 'yes' === $this->rich_snippets_enable && $this->is_enabled() ? true : false ); + } + + /** + * Checks whether review widget is enabled + * + * @return boolean + */ + public function is_review_widget_enabled() { + return ( 'yes' === $this->review_widget_enable && $this->is_enabled() ? true : false ); + } + + public function is_review_reminder_enabled() { + return ( 'yes' === $this->review_reminder_enable && $this->supports( 'reminder' ) && $this->is_enabled() ? true : false ); + } + + public function is_review_reminder_checkbox_enabled() { + return ( 'yes' === $this->review_reminder_checkbox && $this->is_review_reminder_enabled() ? true : false ); + } + + public function product_reviews_visible() { + return ( $this->is_enabled() && $this->is_product_sticker_enabled() ? true : false ); + } + + public function is_product_reviews_enabled() { + return ( 'yes' === $this->reviews_enable && $this->is_enabled() ? true : false ); + } + + public function is_product_sticker_enabled() { + return ( $this->is_product_reviews_enabled() && 'yes' === $this->product_sticker_enable ? true : false ); + } + + public function is_review_sticker_enabled() { + return 'yes' === $this->review_sticker_enable ? true : false; + } + + public function is_product_widget_enabled() { + return ( $this->is_product_reviews_enabled() && 'yes' === $this->product_widget_enable ? true : false ); + } + + public function supports( $type ) { + return ( in_array( $type, $this->supports, true ) ? true : false ); + } + + /** + * Gets Trusted Shops payment gateway by woocommerce payment id + * + * @param integer $payment_method_id + * @return string + */ + public function get_payment_gateway( $payment_method_id ) { + $gateways = WC()->payment_gateways()->payment_gateways(); + + if ( array_key_exists( $payment_method_id, $gateways ) ) { + return $gateways[ $payment_method_id ]->get_method_title(); + } else { + return 'wcOther'; + } + } + + /** + * Returns the average rating by grabbing the rating from the current languages' cache. + * + * @return array + */ + public function get_average_rating() { + $reviews = ( $this->reviews_cache ? $this->reviews_cache : array() ); + + if ( $this->is_multi_language_setup() ) { + $default_language = $this->get_multi_language_compatibility()->get_default_language(); + $current_language = $this->get_multi_language_compatibility()->get_current_language(); + + if ( $current_language !== $default_language ) { + $reviews = ( $this->{"reviews_cache_{$current_language}"} ? $this->{"reviews_cache_{$current_language}"} : array() ); + } + } + + return $reviews; + } + + /** + * Returns the certificate link + * + * @return string + */ + public function get_certificate_link() { + return 'https://www.trustedshops.com/shop/certificate.php?shop_id=' . $this->id; + } + + /** + * Returns add new rating link + * + * @return string + */ + public function get_new_review_link( $email, $order_id ) { + return 'https://www.trustedshops.de/bewertung/bewerten_' . $this->id . '.html&buyerEmail=' . rawurlencode( base64_encode( $email ) ) . '&shopOrderID=' . rawurlencode( base64_encode( $order_id ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode + } + + /** + * Returns the rating link + * + * @return string + */ + public function get_rating_link() { + return 'https://www.trustedshops.de/bewertung/info_' . $this->id . '.html'; + } + + /** + * Gets the attachment id of review widget graphic + * + * @return mixed + */ + public function get_review_widget_attachment() { + return ( ! $this->review_widget_attachment ? false : $this->review_widget_attachment ); + } + + protected function get_product_shopping_data( $id, $attribute ) { + $product = is_numeric( $id ) ? wc_get_product( $id ) : $id; + + if ( ! $product ) { + return false; + } + + $data = wc_ts_get_crud_data( $product, $attribute ); + + if ( empty( $data ) && 'variation' === $product->get_type() ) { + if ( $parent = wc_get_product( wc_ts_get_crud_data( $product, 'parent' ) ) ) { + $data = wc_ts_get_crud_data( $parent, $attribute ); + } + } + + return $data; + } + + public function get_product_image( $id ) { + $product = is_numeric( $id ) ? wc_get_product( $id ) : $id; + + if ( ! $product ) { + return false; + } + + $image = ''; + + if ( is_callable( array( $product, 'get_image_id' ) ) ) { + $image_id = $product->get_image_id(); + $images = wp_get_attachment_image_src( $image_id, 'shop_single' ); + + if ( ! empty( $images ) ) { + $image = $images[0]; + } + } else { + if ( has_post_thumbnail( wc_ts_get_crud_data( $product, 'id' ) ) ) { + $images = wp_get_attachment_image_src( get_post_thumbnail_id( wc_ts_get_crud_data( $product, 'id' ) ), 'shop_single' ); + + if ( ! empty( $images ) ) { + $image = $images[0]; + } + } + } + + return $image; + } + + public function get_product_brand( $id ) { + $product = is_numeric( $id ) ? wc_get_product( $id ) : $id; + + if ( ! $product ) { + return false; + } + + return $product->get_attribute( $this->brand_attribute ); + } + + public function get_product_mpn( $id ) { + return $this->get_product_shopping_data( $id, '_ts_mpn' ); + } + + public function get_product_gtin( $id ) { + return $this->get_product_shopping_data( $id, '_ts_gtin' ); + } + + public function get_product_skus( $id ) { + $product = is_numeric( $id ) ? wc_get_product( $id ) : $id; + $skus = array(); + $skus[] = ( $product->get_sku() ) ? $product->get_sku() : wc_ts_get_crud_data( $product, 'id' ); + + if ( 'grouped' === $product->get_type() ) { + foreach ( $product->get_children() as $child ) { + if ( $child_product = wc_get_product( $child ) ) { + $skus[] = ( $child_product->get_sku() ) ? $child_product->get_sku() : wc_ts_get_crud_data( $child_product, 'id' ); + } + } + } + + return $skus; + } + + public function get_template( $name ) { + $html = ''; + + ob_start(); + wc_get_template( 'trusted-shops/' . str_replace( '_', '-', $name ) . '-tpl.php', array( 'plugin' => $this ) ); + $html = ob_get_clean(); + + /** + * Use strip_tags instead of wp_strip_all_tags because we want to keep JS. + */ + return preg_replace( '/^\h*\v+/m', '', strip_tags( $html ) ); // phpcs:ignore WordPress.WP.AlternativeFunctions.strip_tags_strip_tags + } + + public function get_script( $name, $replace = true, $args = array() ) { + $script = $this->get_template( $name ); + + if ( 'expert' === $this->integration_mode ) { + $option_script = $this->{$name . '_code'}; + + if ( $option_script ) { + $script = $option_script; + } + } + + if ( $replace ) { + $args = wp_parse_args( + $args, + array( + 'id' => $this->id, + 'locale' => $this->get_locale(), + ) + ); + + foreach ( $args as $key => $arg ) { + $search = '{' . $key . '}'; + $replace = $arg; + + if ( is_array( $arg ) ) { + $search = "'{" . $key . "}'"; + + foreach ( $arg as $k => $v ) { + $arg[ $k ] = "'$v'"; + } + + $replace = implode( ',', $arg ); + } + + $script = str_replace( $search, $replace, $script ); + } + } + + return $script; + } + + public function get_selector_attribute( $type, $selector = '' ) { + $element = $this->get_selector_raw( $type, $selector ); + + if ( substr( $element, 0, 1 ) === '.' ) { + $element = substr( $element, 1 ); + } elseif ( substr( $element, 0, 1 ) === '#' ) { + $element = substr( $element, 1 ); + } + + return $element; + } + + public function get_selector_raw( $type, $selector = '' ) { + $element = $this->{$type . '_selector'}; + + if ( empty( $element ) ) { + $element = "#ts_{$type}"; + } + + if ( ! empty( $selector ) ) { + $element = $selector; + } + + return $element; + } + + public function get_selector( $type, $selector = '' ) { + $element = $this->get_selector_raw( $type, $selector ); + $attribute = $this->get_selector_attribute( $type, $selector ); + $is_class = false; + + if ( substr( $element, 0, 1 ) === '.' ) { + $is_class = true; + } + + return $is_class ? 'class="' . esc_attr( $attribute ) . '"' : 'id="' . esc_attr( $attribute ) . '"'; + } + + public function get_product_sticker_code( $replace = true, $args = array() ) { + if ( $replace ) { + $selector = $this->product_sticker_selector; + + $args = wp_parse_args( + $args, + array( + 'element' => empty( $selector ) ? '#ts_product_sticker' : $selector, + 'border_color' => $this->product_sticker_border_color, + 'star_color' => $this->product_sticker_star_color, + 'star_size' => $this->product_sticker_star_size, + ) + ); + } + + return $this->get_script( 'product_sticker', $replace, $args ); + } + + public function get_review_sticker_code( $replace = true, $args = array() ) { + if ( $replace ) { + $args = wp_parse_args( + $args, + array( + 'element' => '#ts_review_sticker', + 'bg_color' => $this->review_sticker_bg_color, + 'font' => $this->review_sticker_font, + 'number' => $this->review_sticker_number, + 'better_than' => $this->review_sticker_better_than, + ) + ); + } + + return $this->get_script( 'review_sticker', $replace, $args ); + } + + public function get_product_widget_code( $replace = true, $args = array() ) { + if ( $replace ) { + $selector = $this->product_widget_selector; + + $args = wp_parse_args( + $args, + array( + 'element' => empty( $selector ) ? '#ts_product_widget' : $selector, + 'star_color' => $this->product_widget_star_color, + 'star_size' => $this->product_widget_star_size, + 'font_size' => $this->product_widget_font_size, + ) + ); + } + + return $this->get_script( 'product_widget', $replace, $args ); + } + + public function get_trustbadge_code( $replace = true, $args = array() ) { + if ( $replace ) { + $args = wp_parse_args( + $args, + array( + 'offset' => $this->trustbadge_y, + 'variant' => 'standard' === $this->trustbadge_variant ? 'reviews' : 'default', + 'disable' => $this->is_trustbadge_enabled() ? 'false' : 'true', + ) + ); + } + + return $this->get_script( 'trustbadge', $replace, $args ); + } + + public function get_rich_snippets_code( $replace = true, $args = array() ) { + if ( $replace ) { + $rating = $this->get_average_rating(); + + $args = apply_filters( + 'woocommerce_trusted_shops_rich_snippets_args', + wp_parse_args( + $args, + array( + 'average' => $rating['avg'], + 'count' => $rating['count'], + 'maximum' => $rating['max'], + 'rating' => $rating, + 'name' => get_bloginfo( 'name' ), + ) + ), + $this + ); + } + + return $this->get_script( 'rich_snippets', $replace, $args ); + } + + public function get_supported_languages() { + return array_keys( $this->get_locale_mapping() ); + } + + protected function get_locale_mapping() { + $supported = array( + 'de' => 'de_DE', + 'en' => 'en_GB', + 'fr' => 'fr_FR', + ); + + return $supported; + } + + public function get_language() { + $locale = $this->get_locale(); + + return substr( $locale, 0, 2 ); + } + + public function get_locale() { + $supported = $this->get_locale_mapping(); + + $locale = 'en_GB'; + $base = substr( function_exists( 'get_user_locale' ) ? get_user_locale() : get_locale(), 0, 2 ); + + if ( isset( $supported[ $base ] ) ) { + $locale = $supported[ $base ]; + } + + return $locale; + } +} + + diff --git a/packages/woocommerce-trusted-shops/includes/class-wc-ts-dependencies.php b/packages/woocommerce-trusted-shops/includes/class-wc-ts-dependencies.php new file mode 100644 index 000000000..a7ac49fb4 --- /dev/null +++ b/packages/woocommerce-trusted-shops/includes/class-wc-ts-dependencies.php @@ -0,0 +1,144 @@ + array( + 'version' => '2.4', + 'version_prefix' => 'woocommerce', + 'name' => 'WooCommerce', + ), + ); + + public static function instance() { + if ( is_null( self::$_instance ) ) { + self::$_instance = new self(); + } + return self::$_instance; + } + + /** + * Cloning is forbidden. + * + * @since 1.0 + */ + public function __clone() { + _doing_it_wrong( __FUNCTION__, esc_html_x( 'Cheating huh?', 'trusted-shops', 'woocommerce-germanized' ), '1.0' ); + } + + /** + * Unserializing instances of this class is forbidden. + * + * @since 1.0 + */ + public function __wakeup() { + _doing_it_wrong( __FUNCTION__, esc_html_x( 'Cheating huh?', 'trusted-shops', 'woocommerce-germanized' ), '1.0' ); + } + + public function __construct() { + + $this->plugins = (array) get_option( 'active_plugins', array() ); + + if ( is_multisite() ) { + $this->plugins = array_merge( $this->plugins, get_site_option( 'active_sitewide_plugins', array() ) ); + } + + foreach ( $this->plugins_required as $plugin => $data ) { + + if ( ! $this->is_plugin_activated( $plugin ) || $this->is_plugin_outdated( $plugin ) ) { + add_action( 'admin_notices', array( $this, 'dependencies_notice' ) ); + $this->loadable = false; + } + } + } + + public function get_plugin_version( $plugin_slug ) { + return get_option( $plugin_slug . '_version' ); + } + + public function is_plugin_outdated( $plugin ) { + $required = ( isset( $this->plugins_required[ $plugin ] ) ? $this->plugins_required[ $plugin ] : false ); + + if ( ! $required ) { + return false; + } + + if ( version_compare( $this->get_plugin_version( $required['version_prefix'] ), $required['version'], '<' ) ) { + return true; + } + + return false; + } + + public function is_plugin_activated( $plugin ) { + + if ( strpos( $plugin, '.php' ) === false ) { + $plugin = trailingslashit( $plugin ) . $plugin . '.php'; + } + + return in_array( $plugin, $this->plugins, true ) || array_key_exists( $plugin, $this->plugins ); + } + + /** + * This method removes accuration from $ver2 if this version is more accurate than $main_ver + */ + public function compare_versions( $main_ver, $ver2, $operator ) { + + $expl_main_ver = explode( '.', $main_ver ); + $expl_ver2 = explode( '.', $ver2 ); + + // Check if ver2 string is more accurate than main_ver + if ( 2 === count( $expl_main_ver ) && count( $expl_ver2 ) > 2 ) { + $new_ver_2 = array_slice( $expl_ver2, 0, 2 ); + $ver2 = implode( '.', $new_ver_2 ); + } + + return version_compare( $main_ver, $ver2, $operator ); + } + + /** + * Checks if WooCommerce is activated + * + * @return boolean true if WooCommerce is activated + */ + public function is_woocommerce_activated() { + return $this->is_plugin_activated( 'woocommerce/woocommerce.php' ); + } + + public function is_wpml_activated() { + return ( $this->is_plugin_activated( 'sitepress-multilingual-cms/sitepress.php' ) && $this->is_plugin_activated( 'woocommerce-multilingual/wpml-woocommerce.php' ) ); + } + + public function woocommerce_version_supports_crud() { + return ( $this->compare_versions( $this->get_plugin_version( 'woocommerce' ), '2.7', '>=' ) ); + } + + public function is_loadable() { + return $this->loadable; + } + + public function dependencies_notice() { + global $dependencies; + $dependencies = $this; + + include_once 'admin/views/html-notice-dependencies.php'; + } + +} + +WC_TS_Dependencies::instance(); diff --git a/packages/woocommerce-trusted-shops/includes/class-wc-ts-install.php b/packages/woocommerce-trusted-shops/includes/class-wc-ts-install.php new file mode 100644 index 000000000..dfdd387d6 --- /dev/null +++ b/packages/woocommerce-trusted-shops/includes/class-wc-ts-install.php @@ -0,0 +1,171 @@ + 'updates/woocommerce-ts-update-3.0.0.php', + '4.0.6' => 'updates/woocommerce-ts-update-4.0.6.php', + ); + + /** + * Hook in tabs. + */ + public function __construct() { + if ( ! Package::is_integration() ) { + add_action( 'admin_init', array( __CLASS__, 'check_version' ), 10 ); + } + + add_action( 'admin_init', array( __CLASS__, 'install_actions' ), 5 ); + } + + /** + * Install actions such as installing pages when a button is clicked. + */ + public static function install_actions() { + if ( ! empty( $_GET['do_update_woocommerce_ts'] ) && current_user_can( 'manage_woocommerce' ) ) { + check_admin_referer( 'wc_ts_db_update', 'wc_ts_db_update_nonce' ); + self::update(); + + // Update complete + delete_option( '_wc_ts_needs_update' ); + } + } + + /** + * check_version function. + * + * @access public + * @return void + */ + public static function check_version() { + if ( ! defined( 'IFRAME_REQUEST' ) && ( get_option( 'woocommerce_trusted_shops_version' ) !== WC_trusted_shops()->version || get_option( 'woocommerce_trusted_shops_db_version' ) !== WC_trusted_shops()->version ) ) { + self::install(); + do_action( 'woocommerce_trusted_shops_updated' ); + } + } + + public static function install_integration() { + self::create_cron_jobs(); + self::update_versions(); + } + + protected static function update_versions() { + // Queue upgrades + $current_version = get_option( 'woocommerce_trusted_shops_version', null ); + $current_db_version = get_option( 'woocommerce_trusted_shops_db_version', null ); + + if ( ! is_null( $current_db_version ) && version_compare( $current_db_version, max( array_keys( self::$db_updates ) ), '<' ) ) { + // Update + update_option( '_wc_ts_needs_update', 1 ); + } else { + self::update_db_version(); + } + + self::update_ts_version(); + + do_action( 'woocommerce_trusted_shops_installed' ); + } + + /** + * Install TS + */ + public static function install() { + // Load Translation for default options + $locale = apply_filters( 'plugin_locale', get_locale(), 'woocommerce-germanized' ); + $mofile = WC_trusted_shops()->plugin_path() . '/i18n/languages/woocommerce-trusted-shops.mo'; + + if ( file_exists( WC_trusted_shops()->plugin_path() . '/i18n/languages/woocommerce-trusted-shops-' . $locale . '.mo' ) ) { + $mofile = WC_trusted_shops()->plugin_path() . '/i18n/languages/woocommerce-trusted-shops-' . $locale . '.mo'; + } + + load_textdomain( 'woocommerce-trusted-shops', $mofile ); + + self::create_options(); + self::create_cron_jobs(); + self::update_versions(); + + // Flush rules after install + flush_rewrite_rules(); + } + + /** + * Update WC version to current + */ + private static function update_ts_version() { + delete_option( 'woocommerce_trusted_shops_version' ); + add_option( 'woocommerce_trusted_shops_version', WC_trusted_shops()->version ); + } + + /** + * Update DB version to current + */ + private static function update_db_version( $version = null ) { + delete_option( 'woocommerce_trusted_shops_db_version' ); + add_option( 'woocommerce_trusted_shops_db_version', is_null( $version ) ? WC_trusted_shops()->version : $version ); + } + + /** + * Handle updates + */ + public static function update() { + $current_db_version = get_option( 'woocommerce_trusted_shops_db_version' ); + + foreach ( self::$db_updates as $version => $updater ) { + if ( version_compare( $current_db_version, $version, '<' ) ) { + include $updater; + self::update_db_version( $version ); + } + } + + self::update_db_version(); + } + + /** + * Create cron jobs (clear them first) + */ + private static function create_cron_jobs() { + // Cron jobs + wp_clear_scheduled_hook( 'woocommerce_gzd_trusted_shops_reviews' ); + wp_schedule_event( time(), 'twicedaily', 'woocommerce_gzd_trusted_shops_reviews' ); + } + + /** + * Default options + * + * Sets up the default options used on the settings page + * + * @access public + */ + private static function create_options() { + // Include settings so that we can run through defaults + $options = apply_filters( 'woocommerce_gzd_installation_default_settings', array() ); + + foreach ( $options as $value ) { + + if ( isset( $value['default'] ) && isset( $value['id'] ) ) { + $autoload = isset( $value['autoload'] ) ? (bool) $value['autoload'] : true; + add_option( $value['id'], $value['default'], '', ( $autoload ? 'yes' : 'no' ) ); + } + } + } + } + +endif; + +return new WC_TS_Install(); diff --git a/packages/woocommerce-trusted-shops/includes/class-wc-ts-settings-handler.php b/packages/woocommerce-trusted-shops/includes/class-wc-ts-settings-handler.php new file mode 100644 index 000000000..d9eb2ef4d --- /dev/null +++ b/packages/woocommerce-trusted-shops/includes/class-wc-ts-settings-handler.php @@ -0,0 +1,77 @@ +id = 'trusted-shops'; + $this->label = _x( 'Trusted Shops', 'trusted-shops', 'woocommerce-germanized' ); + + parent::__construct(); + } + + /** + * Get settings array + * + * @return array + */ + public function get_settings() { + $admin = WC_trusted_shops()->trusted_shops->get_dependency( 'admin' ); + $settings = $admin->get_settings(); + + return $settings; + } + + public function get_settings_for_section_core( $section_id ) { + $admin = WC_trusted_shops()->trusted_shops->get_dependency( 'admin' ); + $settings = $admin->get_settings(); + + return $settings; + } + + public function output() { + global $current_section; + + $settings = $this->get_settings_for_section_core( '' ); + $sidebar = $this->get_sidebar(); + + include_once WC_trusted_shops()->plugin_path() . '/includes/admin/views/html-settings-section.php'; + } + + public function get_sidebar() { + $admin = WC_trusted_shops()->trusted_shops->get_dependency( 'admin' ); + $sidebar = $admin->get_sidebar(); + + return $sidebar; + } + + /** + * Save settings + */ + public function save() { + $settings = $this->get_settings_for_section_core( '' ); + + do_action( 'woocommerce_ts_before_save', $settings ); + WC_Admin_Settings::save_fields( $settings ); + do_action( 'woocommerce_ts_after_save', $settings ); + } + } + +endif; + + diff --git a/packages/woocommerce-trusted-shops/includes/compatibility/class-wc-ts-compatibility-wpml-string-translation.php b/packages/woocommerce-trusted-shops/includes/compatibility/class-wc-ts-compatibility-wpml-string-translation.php new file mode 100644 index 000000000..44e531998 --- /dev/null +++ b/packages/woocommerce-trusted-shops/includes/compatibility/class-wc-ts-compatibility-wpml-string-translation.php @@ -0,0 +1,342 @@ + defined( 'WPML_ST_VERSION' ) ? WPML_ST_VERSION : '1.0', + ) + ); + } + + public function is_activated() { + global $sitepress; + + return defined( 'WPML_ST_VERSION' ) && isset( $sitepress ) ? true : false; + } + + public function load() { + if ( is_admin() ) { + $this->admin_translate_options(); + } + } + + public function get_languages() { + global $sitepress; + $codes = array(); + + if ( isset( $sitepress ) && is_callable( array( $sitepress, 'get_ls_languages' ) ) ) { + $languages = $sitepress->get_ls_languages(); + + if ( ! empty( $languages ) ) { + $codes = array_keys( $languages ); + } + } + + return $codes; + } + + public function get_language_name( $language = '' ) { + global $sitepress; + + if ( empty( $language ) ) { + $language = $this->get_current_language(); + } + + return $sitepress->get_display_language_name( $language ); + } + + public function get_current_language() { + global $sitepress; + + return $sitepress->get_current_language(); + } + + public function get_default_language() { + global $sitepress; + $default = ''; + + if ( isset( $sitepress ) && is_callable( array( $sitepress, 'get_default_language' ) ) ) { + $default = $sitepress->get_default_language(); + } + + return $default; + } + + /** + * Register strings that are translatable within the settings panel. Strings will be loaded in the admin user's language + * within the settings screen only. + * + * @return array + */ + public function get_translatable_options() { + return apply_filters( 'woocommerce_gzd_wpml_translatable_options', array() ); + } + + /** + * By default WPML allow only certain strings to be translated within the administration area (e.g. blog title). + * If you want some translatable strings to be loaded globally within the admin panel use the filter accordingly. + * + * @return array + */ + public function get_translatable_admin_options() { + return apply_filters( 'woocommerce_gzd_wpml_translatable_admin_options', array() ); + } + + public function admin_translate_options() { + $this->set_filters(); + } + + public function set_filters() { + $admin_strings = $this->get_translatable_admin_options(); + + if ( $this->enable_option_filters() ) { + + foreach ( $this->get_translatable_options() as $option => $args ) { + add_filter( 'option_' . $option, array( $this, 'translate_option_filter' ), 10, 2 ); + add_filter( 'pre_update_option_' . $option, array( $this, 'pre_update_translation_filter' ), 10, 3 ); + + wc_ts_remove_class_filter( 'option_' . $option, 'WPML_Admin_Texts', 'icl_st_translate_admin_string', 10 ); + } + } elseif ( ! empty( $admin_strings ) ) { + + foreach ( $admin_strings as $option => $args ) { + add_filter( 'option_' . $option, array( $this, 'translate_option_filter' ), 10, 2 ); + wc_ts_remove_class_filter( 'option_' . $option, 'WPML_Admin_Texts', 'icl_st_translate_admin_string', 10 ); + } + } + } + + protected function enable_option_filters() { + $enable = false; + + if ( isset( $_GET['tab'] ) && ( 'trusted-shops' === $_GET['tab'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $enable = true; + } + + return apply_filters( 'woocommerce_gzd_enable_wpml_string_translation_settings_filters', $enable ); + } + + public function get_string_language( $string_id, $option = '' ) { + if ( $string = $this->get_string_by_id( $string_id ) ) { + return $string->language; + } + + global $WPML_String_Translation; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + + return $WPML_String_Translation->get_current_string_language( $option ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + } + + public function get_string_by_id( $string_id ) { + global $wpdb; + + $string = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}icl_strings WHERE id=%d LIMIT 1", $string_id ) ); + + if ( $string ) { + return $string[0]; + } + + return false; + } + + public function get_string_id( $option, $context = '' ) { + $context = empty( $context ) ? 'admin_texts_' . $option : $context; + + return icl_st_is_registered_string( $context, $option ); + } + + public function get_string_value( $string_id ) { + if ( $string = $this->get_string_by_id( $string_id ) ) { + return $string->value; + } + + return false; + } + + public function update_string_value( $string_id, $value ) { + global $wpdb; + + $value = maybe_serialize( $value ); + + $wpdb->update( "{$wpdb->prefix}icl_strings", array( 'value' => $value ), array( 'id' => $string_id ) ); + } + + public function delete_string_translation( $string_id, $language ) { + global $wpdb; + + $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}icl_string_translations WHERE string_id=%d AND language=%s", $string_id, $language ) ); + } + + public function update_string_translation( $option, $language, $value, $status = '' ) { + if ( empty( $status ) ) { + $status = ICL_TM_COMPLETE; + } + + if ( $string_id = $this->get_string_id( $option ) ) { + icl_add_string_translation( $string_id, $language, $value, $status ); + } + + icl_update_string_translation( $option, $language, $value, $status ); + + // Make sure that the string is stored within the WPML translatable option names + $option_names = get_option( '_icl_admin_option_names', array() ); + $option_names[ $option ] = 1; + + update_option( '_icl_admin_option_names', $option_names ); + } + + public function get_string_translation( $string_id, $language, $status = '' ) { + $translations = icl_get_string_translations_by_id( $string_id ); + $status = empty( $status ) ? ICL_TM_COMPLETE : $status; + + if ( isset( $translations[ $language ] ) && $translations[ $language ]['status'] === $status ) { + return $translations[ $language ]['value']; + } + + return false; + } + + public function get_translated_string( $option, $language, $context = '' ) { + $value = null; + + if ( $string_id = $this->get_string_id( $option, $context ) ) { + $value = $this->get_string_translation( $string_id, $language ); + } + + return $value; + } + + public function register_string( $option, $value, $context = '' ) { + $context = empty( $context ) ? 'admin_texts_' . $option : $context; + + return icl_register_string( $context, $option, $value ); + } + + public function pre_update_translation_filter( $new_value, $old_value, $option ) { + $string_options = $this->get_translatable_options(); + + if ( is_array( $new_value ) || is_array( $string_options[ $option ] ) ) { + + if ( ! is_array( $new_value ) ) { + $new_value = array(); + } + + $args = $string_options[ $option ]; + + foreach ( $new_value as $id => $options ) { + foreach ( $options as $key => $value ) { + if ( in_array( $key, $args ) ) { // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict + $old_value_internal = isset( $old_value[ $id ][ $key ] ) ? $old_value[ $id ][ $key ] : ''; + $new_value[ $id ][ $key ] = $this->pre_update_translation( $value, $old_value_internal, "[{$option}][{$id}]{$key}", "admin_texts_{$option}" ); + } + } + } + + return $new_value; + } else { + return $this->pre_update_translation( $new_value, $old_value, $option ); + } + } + + protected function pre_update_translation( $new_value, $old_value, $option, $context = '' ) { + $org_string_id = $this->get_string_id( $option, $context ); + $strings_language = $this->get_string_language( $org_string_id, $option ); + $return_value = $old_value; + + if ( $strings_language === $this->get_current_language() || 'all' === $this->get_current_language() ) { + + $current_string_value = $this->get_string_value( $org_string_id ); + + // Update original string value + if ( $org_string_id && ( $new_value !== $old_value || $current_string_value !== $new_value ) ) { + $this->update_string_value( $org_string_id, $new_value ); + } + + $return_value = $new_value; + + } else { + $update_translation = true; + + if ( $org_string_id ) { + $org_string = $this->get_string_value( $org_string_id ); + + /** + * Remove translation if it equals original string + * Use woocommerce_gzd_wpml_remove_translation_empty_equal filter to disallow string deletion which results in "real" option translations + */ + if ( ( $org_string === $new_value || empty( $new_value ) ) && apply_filters( 'woocommerce_gzd_wpml_remove_translation_empty_equal', true, $option, $new_value, $old_value ) ) { + $this->delete_string_translation( $org_string_id, $this->get_current_language() ); + + $return_value = $old_value; + $update_translation = false; + } + } + + if ( $update_translation ) { + $this->update_string_translation( $option, $this->get_current_language(), $new_value ); + } + } + + // Allow WPML to delete the cache + do_action( "update_option_{$option}", $old_value, $return_value, $option ); + + return $return_value; + } + + public function translate_option_filter( $org_value, $option ) { + $string_options = $this->get_translatable_options(); + + if ( is_array( $org_value ) || is_array( $string_options[ $option ] ) ) { + + if ( ! is_array( $org_value ) ) { + $org_value = array(); + } + + $args = $string_options[ $option ]; + + foreach ( $org_value as $id => $options ) { + foreach ( $options as $key => $value ) { + if ( in_array( $key, $args ) ) { // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict + $org_value[ $id ][ $key ] = $this->translate_option( $value, "[{$option}][{$id}]{$key}", "admin_texts_{$option}" ); + } + } + } + + return $org_value; + } else { + return $this->translate_option( $org_value, $option ); + } + } + + protected function translate_option( $org_value, $option, $context = '' ) { + $string_id = $this->get_string_id( $option, $context ); + $language = $this->get_current_language(); + + if ( ! $string_id ) { + $string_id = $this->register_string( $option, $org_value, $context ); + } + + $translation = $this->get_string_translation( $string_id, $language ); + + if ( false !== $translation ) { + $org_value = $translation; + } + + return $org_value; + } + + public function pre_update_translate_checkboxes( $new_value, $old_value, $option ) { + return $new_value; + } +} diff --git a/packages/woocommerce-trusted-shops/includes/emails/class-wc-ts-email-customer-trusted-shops.php b/packages/woocommerce-trusted-shops/includes/emails/class-wc-ts-email-customer-trusted-shops.php new file mode 100644 index 000000000..1bbf41b38 --- /dev/null +++ b/packages/woocommerce-trusted-shops/includes/emails/class-wc-ts-email-customer-trusted-shops.php @@ -0,0 +1,165 @@ +id = 'customer_trusted_shops'; + $this->title = _x( 'Trusted Shops Review Reminder', 'trusted-shops', 'woocommerce-germanized' ); + $this->description = _x( 'This E-Mail is being sent to a customer to remind him about the possibility to leave a review at Trusted Shops.', 'trusted-shops', 'woocommerce-germanized' ); + + $this->template_html = 'emails/customer-trusted-shops.php'; + $this->template_plain = 'emails/plain/customer-trusted-shops.php'; + $this->helper = function_exists( 'wc_gzd_get_email_helper' ) ? wc_gzd_get_email_helper( $this ) : false; + + // Triggers for this email + add_action( 'woocommerce_germanized_trusted_shops_review_notification', array( $this, 'trigger' ) ); + + $this->placeholders = array( + '{site_title}' => $this->get_blogname(), + '{order_number}' => '', + '{order_date}' => '', + ); + + // Call parent constuctor + parent::__construct(); + + $this->customer_email = true; + } + + /** + * Get email subject. + * + * @since 3.1.0 + * @return string + */ + public function get_default_subject() { + return _x( 'Please rate your {site_title} order from {order_date}', 'trusted-shops', 'woocommerce-germanized' ); + } + + /** + * Get email heading. + * + * @since 3.1.0 + * @return string + */ + public function get_default_heading() { + return _x( 'Please rate your Order', 'trusted-shops', 'woocommerce-germanized' ); + } + + /** + * trigger function. + * + * @access public + * @return void + */ + public function trigger( $order_id ) { + if ( $this->helper ) { + $this->helper->setup_locale(); + } else { + $this->setup_locale(); + } + + if ( $order_id ) { + $this->object = wc_get_order( $order_id ); + $this->recipient = wc_ts_get_crud_data( $this->object, 'billing_email' ); + + $this->placeholders['{order_date}'] = wc_gzd_get_order_date( $this->object, wc_date_format() ); + $this->placeholders['{order_number}'] = $this->object->get_order_number(); + } + + if ( $this->helper ) { + $this->helper->setup_email_locale(); + } + + if ( $this->is_enabled() && $this->get_recipient() ) { + $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() ); + } + + if ( $this->helper ) { + $this->helper->restore_email_locale(); + $this->helper->restore_locale(); + } else { + $this->restore_locale(); + } + } + + /** + * Return content from the additional_content field. + * + * Displayed above the footer. + * + * @since 2.0.4 + * @return string + */ + public function get_additional_content() { + if ( is_callable( 'parent::get_additional_content' ) ) { + return parent::get_additional_content(); + } + + return ''; + } + + /** + * get_content_html function. + * + * @access public + * @return string + */ + public function get_content_html() { + return wc_get_template_html( + $this->template_html, + array( + 'order' => $this->object, + 'email_heading' => $this->get_heading(), + 'additional_content' => $this->get_additional_content(), + 'sent_to_admin' => false, + 'plain_text' => false, + 'email' => $this, + ) + ); + } + + /** + * Get content plain. + * + * @return string + */ + public function get_content_plain() { + return wc_get_template_html( + $this->template_plain, + array( + 'order' => $this->object, + 'email_heading' => $this->get_heading(), + 'additional_content' => $this->get_additional_content(), + 'sent_to_admin' => false, + 'plain_text' => false, + 'email' => $this, + ) + ); + } + } + +endif; + +return new WC_TS_Email_Customer_Trusted_Shops(); diff --git a/packages/woocommerce-trusted-shops/includes/updates/woocommerce-ts-update-3.0.0.php b/packages/woocommerce-trusted-shops/includes/updates/woocommerce-ts-update-3.0.0.php new file mode 100644 index 000000000..c36776453 --- /dev/null +++ b/packages/woocommerce-trusted-shops/includes/updates/woocommerce-ts-update-3.0.0.php @@ -0,0 +1,23 @@ +get_wc_product(); + } + + $value = null; + + $getter = substr( $key, 0, 3 ) === 'get' ? $key : "get_$key"; + $key = substr( $key, 0, 3 ) === 'get' ? substr( $key, 3 ) : $key; + + if ( 'id' === $key && is_callable( array( $object, 'is_type' ) ) && $object->is_type( 'variation' ) && ! wc_ts_woocommerce_supports_crud() ) { + $key = 'variation_id'; + } elseif ( 'parent' === $key && is_callable( array( $object, 'is_type' ) ) && $object->is_type( 'variation' ) && ! wc_ts_woocommerce_supports_crud() ) { + // Set getter to parent so that it is not being used for pre 2.7 + $key = 'id'; + $getter = 'parent'; + } + + $getter_mapping = array( + 'parent' => 'get_parent_id', + 'completed_date' => 'get_date_completed', + 'order_date' => 'get_date_created', + 'product_type' => 'get_type', + 'order_type' => 'get_type', + ); + + if ( array_key_exists( $key, $getter_mapping ) ) { + $getter = $getter_mapping[ $key ]; + } + + if ( is_callable( array( $object, $getter ) ) ) { + $reflection = new ReflectionMethod( $object, $getter ); + if ( $reflection->isPublic() ) { + $value = $object->{$getter}(); + } + } elseif ( wc_ts_woocommerce_supports_crud() ) { + // Prefix meta if suppress_suffix is not set + if ( substr( $key, 0, 1 ) !== '_' && ! $suppress_suffix ) { + $key = '_' . $key; + } + + $value = $object->get_meta( $key ); + } else { + $key = substr( $key, 0, 1 ) === '_' ? substr( $key, 1 ) : $key; + $value = $object->{$key}; + } + + return $value; + } +} + +if ( ! function_exists( 'wc_ts_woocommerce_supports_crud' ) ) { + + function wc_ts_woocommerce_supports_crud() { + return WC_TS_Dependencies::instance()->woocommerce_version_supports_crud(); + } +} + +if ( ! function_exists( 'wc_ts_help_tip' ) ) { + + function wc_ts_help_tip( $tip, $allow_html = false ) { + if ( function_exists( 'wc_help_tip' ) ) { + return wc_help_tip( $tip, $allow_html ); + } + + return '[?]'; + } +} + +if ( ! function_exists( 'wc_ts_set_crud_data' ) ) { + + function wc_ts_set_crud_data( $object, $key, $value ) { + if ( wc_ts_woocommerce_supports_crud() ) { + + $key_unprefixed = substr( $key, 0, 1 ) === '_' ? substr( $key, 1 ) : $key; + $setter = substr( $key_unprefixed, 0, 3 ) === 'set' ? $key : "set_{$key_unprefixed}"; + + if ( is_callable( array( $object, $setter ) ) ) { + $reflection = new ReflectionMethod( $object, $setter ); + if ( $reflection->isPublic() ) { + $object->{$setter}( $value ); + } + } else { + $object = wc_ts_set_crud_meta_data( $object, $key, $value ); + } + } else { + $object = wc_ts_set_crud_meta_data( $object, $key, $value ); + } + return $object; + } +} + +if ( ! function_exists( 'wc_ts_set_crud_meta_data' ) ) { + function wc_ts_set_crud_meta_data( $object, $key, $value ) { + + if ( wc_ts_woocommerce_supports_crud() ) { + $object->update_meta_data( $key, $value ); + } else { + update_post_meta( wc_ts_get_crud_data( $object, 'id' ), $key, $value ); + } + return $object; + } +} + +if ( ! function_exists( 'wc_ts_get_order_date' ) ) { + + function wc_ts_get_order_date( $order, $format = '' ) { + $date_formatted = ''; + + if ( function_exists( 'wc_format_datetime' ) ) { + return wc_format_datetime( $order->get_date_created(), $format ); + } else { + $date = $order->order_date; + } + + if ( empty( $format ) ) { + $format = get_option( 'date_format' ); + } + + if ( ! empty( $date ) ) { + $date_formatted = date_i18n( $format, strtotime( $date ) ); + } + + return $date_formatted; + } +} + +if ( ! function_exists( 'wc_ts_get_order_currency' ) ) { + + function wc_ts_get_order_currency( $order ) { + if ( wc_ts_woocommerce_supports_crud() ) { + return $order->get_currency(); + } + + return $order->get_order_currency(); + } +} + +if ( ! function_exists( 'wc_ts_get_order_language' ) ) { + + function wc_ts_get_order_language( $order ) { + $order_id = is_numeric( $order ) ? $order : wc_ts_get_crud_data( $order, 'id' ); + + return get_post_meta( $order_id, 'wpml_language', true ); + } +} + +if ( ! function_exists( 'wc_ts_switch_language' ) ) { + + function wc_ts_switch_language( $lang, $set_default = false ) { + global $sitepress; + global $wc_ts_original_lang; + + if ( $set_default ) { + $wc_ts_original_lang = $lang; + } + + if ( isset( $sitepress ) && is_callable( array( $sitepress, 'get_current_language' ) ) && is_callable( array( $sitepress, 'switch_lang' ) ) ) { + if ( $sitepress->get_current_language() !== $lang ) { + + $sitepress->switch_lang( $lang, true ); + + // Somehow WPML doesn't automatically change the locale + if ( is_callable( array( $sitepress, 'reset_locale_utils_cache' ) ) ) { + $sitepress->reset_locale_utils_cache(); + } + + if ( function_exists( 'switch_to_locale' ) ) { + switch_to_locale( get_locale() ); + + // Filter on plugin_locale so load_plugin_textdomain loads the correct locale. + add_filter( 'plugin_locale', 'get_locale' ); + + // Init WC locale. + WC()->load_plugin_textdomain(); + WC_trusted_shops()->load_plugin_textdomain(); + WC_trusted_shops()->trusted_shops->refresh(); + } + + do_action( 'woocommerce_gzd_trusted_shops_switched_language', $lang, $wc_ts_original_lang ); + } + } + + do_action( 'woocommerce_gzd_trusted_shops_switch_language', $lang, $wc_ts_original_lang ); + } +} + +if ( ! function_exists( 'wc_ts_restore_language' ) ) { + + function wc_ts_restore_language() { + global $wc_ts_original_lang; + + if ( isset( $wc_ts_original_lang ) && ! empty( $wc_ts_original_lang ) ) { + wc_ts_switch_language( $wc_ts_original_lang ); + } + } +} + +if ( ! function_exists( 'wc_ts_remove_class_filter' ) ) { + /** + * Remove Class Filter Without Access to Class Object + * + * In order to use the core WordPress remove_filter() on a filter added with the callback + * to a class, you either have to have access to that class object, or it has to be a call + * to a static method. This method allows you to remove filters with a callback to a class + * you don't have access to. + * + * Works with WordPress 1.2+ (4.7+ support added 9-19-2016) + * Updated 2-27-2017 to use internal WordPress removal for 4.7+ (to prevent PHP warnings output) + * + * @param string $tag Filter to remove + * @param string $class_name Class name for the filter's callback + * @param string $method_name Method name for the filter's callback + * @param int $priority Priority of the filter (default 10) + * + * @return bool Whether the function is removed. + */ + function wc_ts_remove_class_filter( $tag, $class_name = '', $method_name = '', $priority = 10 ) { + global $wp_filter; + + // Check that filter actually exists first + if ( ! isset( $wp_filter[ $tag ] ) ) { + return false; + } + + /** + * If filter config is an object, means we're using WordPress 4.7+ and the config is no longer + * a simple array, rather it is an object that implements the ArrayAccess interface. + * + * To be backwards compatible, we set $callbacks equal to the correct array as a reference (so $wp_filter is updated) + * + * @see https://make.wordpress.org/core/2016/09/08/wp_hook-next-generation-actions-and-filters/ + */ + if ( is_object( $wp_filter[ $tag ] ) && isset( $wp_filter[ $tag ]->callbacks ) ) { + // Create $fob object from filter tag, to use below + $fob = $wp_filter[ $tag ]; + $callbacks = &$wp_filter[ $tag ]->callbacks; + } else { + $callbacks = &$wp_filter[ $tag ]; + } + + // Exit if there aren't any callbacks for specified priority + if ( ! isset( $callbacks[ $priority ] ) || empty( $callbacks[ $priority ] ) ) { + return false; + } + + // Loop through each filter for the specified priority, looking for our class & method + foreach ( (array) $callbacks[ $priority ] as $filter_id => $filter ) { + + // Filter should always be an array - array( $this, 'method' ), if not goto next + if ( ! isset( $filter['function'] ) || ! is_array( $filter['function'] ) ) { + continue; + } + + // If first value in array is not an object, it can't be a class + if ( ! is_object( $filter['function'][0] ) ) { + continue; + } + + // Method doesn't match the one we're looking for, goto next + if ( $filter['function'][1] !== $method_name ) { + continue; + } + + // Method matched, now let's check the Class + if ( get_class( $filter['function'][0] ) === $class_name ) { + + // WordPress 4.7+ use core remove_filter() since we found the class object + if ( isset( $fob ) ) { + // Handles removing filter, reseting callback priority keys mid-iteration, etc. + $fob->remove_filter( $tag, $filter['function'], $priority ); + + } else { + // Use legacy removal process (pre 4.7) + unset( $callbacks[ $priority ][ $filter_id ] ); + // and if it was the only filter in that priority, unset that priority + if ( empty( $callbacks[ $priority ] ) ) { + unset( $callbacks[ $priority ] ); + } + // and if the only filter for that tag, set the tag to an empty array + if ( empty( $callbacks ) ) { + $callbacks = array(); + } + // Remove this filter from merged_filters, which specifies if filters have been sorted + unset( $GLOBALS['merged_filters'][ $tag ] ); + } + + return true; + } + } + + return false; + } +} + +if ( ! function_exists( 'wc_ts_remove_class_action' ) ) { + /** + * Remove Class Action Without Access to Class Object + * + * In order to use the core WordPress remove_action() on an action added with the callback + * to a class, you either have to have access to that class object, or it has to be a call + * to a static method. This method allows you to remove actions with a callback to a class + * you don't have access to. + * + * Works with WordPress 1.2+ (4.7+ support added 9-19-2016) + * + * @param string $tag Action to remove + * @param string $class_name Class name for the action's callback + * @param string $method_name Method name for the action's callback + * @param int $priority Priority of the action (default 10) + * + * @return bool Whether the function is removed. + */ + function wc_ts_remove_class_action( $tag, $class_name = '', $method_name = '', $priority = 10 ) { + wc_ts_remove_class_filter( $tag, $class_name, $method_name, $priority ); + } +} diff --git a/packages/woocommerce-trusted-shops/includes/widgets/class-wc-trusted-shops-widget-review-sticker.php b/packages/woocommerce-trusted-shops/includes/widgets/class-wc-trusted-shops-widget-review-sticker.php new file mode 100644 index 000000000..6a39d08ce --- /dev/null +++ b/packages/woocommerce-trusted-shops/includes/widgets/class-wc-trusted-shops-widget-review-sticker.php @@ -0,0 +1,66 @@ +widget_cssclass = 'woocommerce woocommerce_gzd widget_trusted_shops_review_sticker'; + $this->widget_description = _x( 'Show your TS shop review sticker.', 'trusted-shops', 'woocommerce-germanized' ); + $this->widget_id = 'woocommerce_gzd_widget_trusted_shops_shop_review_sticker'; + $this->widget_name = _x( 'Trusted Shops Shop Review Sticker', 'trusted-shops', 'woocommerce-germanized' ); + $this->settings = array( + 'title' => array( + 'type' => 'text', + 'std' => _x( 'Trusted Shops Reviews', 'trusted-shops', 'woocommerce-germanized' ), + 'label' => _x( 'Title', 'trusted-shops', 'woocommerce-germanized' ), + ), + ); + parent::__construct(); + } + + /** + * widget function. + * + * @see WP_Widget + * @access public + * @param array $args + * @param array $instance + * @return void + */ + public function widget( $args, $instance ) { + extract( $args ); // phpcs:ignore WordPress.PHP.DontExtract.extract_extract + + $element = "#ts_review_sticker_{$this->number}"; + + $title = apply_filters( 'widget_title', empty( $instance['title'] ) ? _x( 'Trusted Shops Reviews', 'trusted-shops', 'woocommerce-germanized' ) : $instance['title'], $instance, $this->id_base ); + + echo wp_kses_post( $before_widget ); + + if ( $title ) { + echo wp_kses_post( $before_title . $title . $after_title ); + } + + echo '
'; + + echo do_shortcode( '[trusted_shops_review_sticker element="' . $element . '"]' ); + + echo '
'; + + echo wp_kses_post( $after_widget ); + } +} + + diff --git a/packages/woocommerce-trusted-shops/license.txt b/packages/woocommerce-trusted-shops/license.txt new file mode 100644 index 000000000..e4e3f0c5f --- /dev/null +++ b/packages/woocommerce-trusted-shops/license.txt @@ -0,0 +1,699 @@ +WooCommerce Trusted Shops + +Copyright 2011 by the contributors + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +This program incorporates work covered by the following copyright and +permission notices: + + WooCommerce + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright © 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright © + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright © + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file diff --git a/packages/woocommerce-trusted-shops/readme.txt b/packages/woocommerce-trusted-shops/readme.txt new file mode 100644 index 000000000..cf8e9edd9 --- /dev/null +++ b/packages/woocommerce-trusted-shops/readme.txt @@ -0,0 +1,152 @@ +=== Trustbadge Reviews for WooCommerce === +Contributors: vendidero, trustbadge +Tags: advanced reviews, badge, best reviews, business ratings, business reviews, confirm email reviews, google rating, google shopping, product ratings, product reviews, rate products, rating summary, Rating Widget, ratings, reputation, review widget, review, reviews easy, reviews, rich snippets, seal, seo, star rating, stars, trust, trustbadge, trusted reviews, trusted shops, ts, user rating, user reviews, woocommerce trusted shops, woocommerce +Donate link: http://www.trustbadge.com +Requires at least: 4.9 +Tested up to: 5.9 +WC requires at least: 3.4 +WC tested up to: 6.1 +Stable tag: 4.0.15 +Requires PHP: 5.6 +License: GPLv3 +License URI: http://www.gnu.org/licenses/gpl-3.0.html + +Show that your customers love you with reviews in your online store and boost your business with the free Trustbadge Reviews Plugin for WooCommerce. +== Description == + += Building trust - in just 5 minutes! = + +The well-known Trustmark, the Buyer Protection and the authentic reviews from Trusted Shops have stood for trust for over 20 years. More than 30,000 online shops throughout Europe use our Trust solutions for more traffic, higher sales and better conversion rates. + +Trustbadge Reviews for WooCommerce is the easiest and fastest way to convince visitors of the trustworthiness of your online shop. The simple installation guarantees product use in just 5 minutes and usually requires little to no prior technical knowledge. With our extension you are always technically up to date and have no additional maintenance effort. + +Your benefit: With just a few clicks, visitors to your online shop can see trust elements such as the Trustbadge or other on-site widgets, can benefit from buyer protection and are automatically asked for feedback after placing an order. + += All features at a glance: = + +* Show Trustbadge, integrate Buyer Protection & collect shop reviews +* Show Shop Review Sticker with rating comments +* Collect and display Product Reviews +* Configure multi-shops with multiple Trusted Shops IDs + +Please note: To use the extension Trustbadge Reviews for WooCommerce, you need an existing Trusted Shops membership. You can find out more about the products and benefits of Trusted Shops on our [website](https://business.trustedshops.com/) or by calling: +44 23364 5906 + +== Installation == + += Minimal Requirements = + +* WordPress 4.9 or newer +* WooCommerce 3.0 +* PHP Version 5.6 or newer + += Shortcodes = + +`[trusted_shops_rich_snippets]` +Use this shortcode to embed your updated Trusted Shops Rich Snippets within your post/page or product description. + +`[trusted_shops_reviews]` +Embed your Trusted Shops Review Image within your post/page or product description. + +`[trusted_shops_badge]` +Embed your Trusted Shops Badge within your content. + +== Frequently Asked Questions == + += Do you need help with Trustbadge Reviews for WooCommerce? = +A detailed integration manual can be found in our [Help Centre](https://help.etrusted.com/hc/en-gb/articles/360046269991-Using-Trusted-Shops-with-WooCommerce). + += How can I become a Trusted Shops Member? = +You can find out more about the products and benefits of Trusted Shops on our [website](https://business.trustedshops.com/) or by calling: +44 23364 5906 + +== Screenshots == + +1. Screenshot 1 +2. Screenshot 2 +3. Screenshot 3 +4. Screenshot 4 +5. Screenshot 5 + +== Changelog == += 4.0.15 = +* Improvement: PHP Code Sniffer fixes + += 4.0.14 = +* Improvement: Harden URL escaping + += 4.0.13 = +* Improvement: Force parent GTIN/MPN within trusted shops wrapper + += 4.0.12 = +* Fix: Custom selectors defaults +* Improvement: Updating default settings when switching to standard mode + += 4.0.11 = +* Improvement: CSV export format +* Improvement: WP 5.8, Woo 5.5 support + += 4.0.8 = +* Improvement: Use Woo payment method title +* Improvement: Better function exists checking + += 4.0.4 = +* Improvement: Indicate Woo 4.0 + WP 5.4 support +* Improvement: Removed legacy support +* Fix: Email schedule +* Fix: Force review widget template override + += 4.0.0 = +* Improvement: Legacy code removals +* Improvement: PHP 5.6 +* Improvement: WC 3.8 support + += 3.0.3 = +* Improvement: Indicate correct module name in templates for suppport purposes + += 3.0.2 = +* Improvement: Do only replace Woo reviews when product sticker is enabled + += 3.0.1 = +* Fix: Autoloading class + += 3.0.0 = +* Feature - Better WPML support +* Feature - Better setting control +* Improvement - Code refactoring + += 2.2.0 = +* Feature - WC 3.2 Compatibility +* Fix - Review stars not showing on product page + += 2.0.1 = +* Feature - WC 2.7 beta compatibility +* Feature - Rich snippets image +* Feature - Brand/MPN attribute +* Fix - Template globals filter removal +* Fix - Settings show/hide + += 2.0.3 = +* Fix - Better Review Widget Update + += 2.0.2 = +* Fix - Star Size Option + += 2.0.1 = +* Fix - Review Collector Export + += 2.0.0 = +* Feature - Product Reviews +* Feature - Product Review Sticker/Stars +* Feature - GTIN for Product Reviews +* Feature - In Standard Mode no need to insert JS Trustbadge Code +* Feature - Expert Mode for code adjustments + += 1.1.0 = +* Feature - Trusted Shops Review Collector + += 1.0.0 = +* Feature - Trusted Shops Integration + +== Upgrade Notice == + += 1.0.0 = +no upgrade - just install :) diff --git a/packages/woocommerce-trusted-shops/src/Package.php b/packages/woocommerce-trusted-shops/src/Package.php new file mode 100644 index 000000000..77bd2c54d --- /dev/null +++ b/packages/woocommerce-trusted-shops/src/Package.php @@ -0,0 +1,113 @@ + +
+

+
+ version, '3.1', '>=' ) ? true : false; + } + + public static function is_integration() { + return class_exists( 'WooCommerce_Germanized' ) ? true : false; + } + + private static function includes() { + include_once self::get_path() . '/includes/class-wc-trusted-shops-core.php'; + } + + public static function init_hooks() {} + + /** + * Return the version of the package. + * + * @return string + */ + public static function get_version() { + return self::VERSION; + } + + /** + * Return the path to the package. + * + * @return string + */ + public static function get_path() { + return dirname( __DIR__ ); + } + + /** + * Return the path to the package. + * + * @return string + */ + public static function get_url() { + return plugins_url( '', __DIR__ ); + } + + public static function get_assets_url() { + return self::get_url() . '/assets'; + } + + private static function define_constant( $name, $value ) { + if ( ! defined( $name ) ) { + define( $name, $value ); + } + } +} diff --git a/packages/woocommerce-trusted-shops/templates/emails/cancel-review-reminder.php b/packages/woocommerce-trusted-shops/templates/emails/cancel-review-reminder.php new file mode 100644 index 000000000..55f6099f5 --- /dev/null +++ b/packages/woocommerce-trusted-shops/templates/emails/cancel-review-reminder.php @@ -0,0 +1,16 @@ + + +
+

' . esc_html_x( 'cancel review reminder', 'trusted-shops', 'woocommerce-germanized' ) . '' ) ); ?>

+
diff --git a/packages/woocommerce-trusted-shops/templates/emails/customer-trusted-shops.php b/packages/woocommerce-trusted-shops/templates/emails/customer-trusted-shops.php new file mode 100644 index 000000000..fb1674662 --- /dev/null +++ b/packages/woocommerce-trusted-shops/templates/emails/customer-trusted-shops.php @@ -0,0 +1,37 @@ + + + + +

+

+ + + + + +
+ + + + diff --git a/packages/woocommerce-trusted-shops/templates/emails/plain/customer-trusted-shops.php b/packages/woocommerce-trusted-shops/templates/emails/plain/customer-trusted-shops.php new file mode 100644 index 000000000..f8666ed09 --- /dev/null +++ b/packages/woocommerce-trusted-shops/templates/emails/plain/customer-trusted-shops.php @@ -0,0 +1,34 @@ +trusted_shops->get_new_review_link( wc_ts_get_crud_data( $order, 'billing_email' ), $order->get_order_number() ) ) . "\n\n"; + +echo "\n\n----------------------------------------\n\n"; + +/** + * Show user-defined additional content - this is set in each email's settings. + */ +if ( $additional_content ) { + echo esc_html( wp_strip_all_tags( wptexturize( $additional_content ) ) ); + echo "\n\n----------------------------------------\n\n"; +} + +echo wp_kses_post( apply_filters( 'woocommerce_email_footer_text', get_option( 'woocommerce_email_footer_text' ) ) ); diff --git a/packages/woocommerce-trusted-shops/templates/trusted-shops/product-sticker-tpl.php b/packages/woocommerce-trusted-shops/templates/trusted-shops/product-sticker-tpl.php new file mode 100644 index 000000000..c9635f19e --- /dev/null +++ b/packages/woocommerce-trusted-shops/templates/trusted-shops/product-sticker-tpl.php @@ -0,0 +1,34 @@ + + + diff --git a/packages/woocommerce-trusted-shops/templates/trusted-shops/product-sticker.php b/packages/woocommerce-trusted-shops/templates/trusted-shops/product-sticker.php new file mode 100644 index 000000000..b7a3517d4 --- /dev/null +++ b/packages/woocommerce-trusted-shops/templates/trusted-shops/product-sticker.php @@ -0,0 +1,21 @@ +get_product_skus( $post->ID ); +?> + +
get_selector( 'product_sticker' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
+ + diff --git a/packages/woocommerce-trusted-shops/templates/trusted-shops/product-widget-tpl.php b/packages/woocommerce-trusted-shops/templates/trusted-shops/product-widget-tpl.php new file mode 100644 index 000000000..1e27f02eb --- /dev/null +++ b/packages/woocommerce-trusted-shops/templates/trusted-shops/product-widget-tpl.php @@ -0,0 +1,22 @@ + + diff --git a/packages/woocommerce-trusted-shops/templates/trusted-shops/product-widget.php b/packages/woocommerce-trusted-shops/templates/trusted-shops/product-widget.php new file mode 100644 index 000000000..6e3db98ef --- /dev/null +++ b/packages/woocommerce-trusted-shops/templates/trusted-shops/product-widget.php @@ -0,0 +1,25 @@ +ID ); +$plugin = isset( $plugin ) ? $plugin : WC_trusted_shops()->trusted_shops; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited +$skus = $plugin->get_product_skus( $post->ID ); +?> + +
get_selector( 'product_widget' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
+ + + + diff --git a/packages/woocommerce-trusted-shops/templates/trusted-shops/review-sticker-tpl.php b/packages/woocommerce-trusted-shops/templates/trusted-shops/review-sticker-tpl.php new file mode 100644 index 000000000..0ac4e3230 --- /dev/null +++ b/packages/woocommerce-trusted-shops/templates/trusted-shops/review-sticker-tpl.php @@ -0,0 +1,33 @@ + + + diff --git a/packages/woocommerce-trusted-shops/templates/trusted-shops/review-sticker.php b/packages/woocommerce-trusted-shops/templates/trusted-shops/review-sticker.php new file mode 100644 index 000000000..2faaacdfd --- /dev/null +++ b/packages/woocommerce-trusted-shops/templates/trusted-shops/review-sticker.php @@ -0,0 +1,19 @@ + + +
get_selector( 'review_sticker', $element ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
+ + diff --git a/packages/woocommerce-trusted-shops/templates/trusted-shops/rich-snippets-tpl.php b/packages/woocommerce-trusted-shops/templates/trusted-shops/rich-snippets-tpl.php new file mode 100644 index 000000000..8457ab483 --- /dev/null +++ b/packages/woocommerce-trusted-shops/templates/trusted-shops/rich-snippets-tpl.php @@ -0,0 +1,22 @@ + + diff --git a/packages/woocommerce-trusted-shops/templates/trusted-shops/rich-snippets.php b/packages/woocommerce-trusted-shops/templates/trusted-shops/rich-snippets.php new file mode 100644 index 000000000..89cd06814 --- /dev/null +++ b/packages/woocommerce-trusted-shops/templates/trusted-shops/rich-snippets.php @@ -0,0 +1,18 @@ + + + diff --git a/packages/woocommerce-trusted-shops/templates/trusted-shops/thankyou.php b/packages/woocommerce-trusted-shops/templates/trusted-shops/thankyou.php new file mode 100644 index 000000000..2f7761b41 --- /dev/null +++ b/packages/woocommerce-trusted-shops/templates/trusted-shops/thankyou.php @@ -0,0 +1,57 @@ + + + diff --git a/packages/woocommerce-trusted-shops/templates/trusted-shops/trustbadge-tpl.php b/packages/woocommerce-trusted-shops/templates/trusted-shops/trustbadge-tpl.php new file mode 100644 index 000000000..71ed15bd1 --- /dev/null +++ b/packages/woocommerce-trusted-shops/templates/trusted-shops/trustbadge-tpl.php @@ -0,0 +1,29 @@ + + + diff --git a/packages/woocommerce-trusted-shops/templates/trusted-shops/trustbadge.php b/packages/woocommerce-trusted-shops/templates/trusted-shops/trustbadge.php new file mode 100644 index 000000000..b5588808f --- /dev/null +++ b/packages/woocommerce-trusted-shops/templates/trusted-shops/trustbadge.php @@ -0,0 +1,17 @@ + + + diff --git a/packages/woocommerce-trusted-shops/woocommerce-trusted-shops.php b/packages/woocommerce-trusted-shops/woocommerce-trusted-shops.php new file mode 100644 index 000000000..941809722 --- /dev/null +++ b/packages/woocommerce-trusted-shops/woocommerce-trusted-shops.php @@ -0,0 +1,73 @@ + +
+

+ composer install', + '' . esc_html( str_replace( ABSPATH, '', __DIR__ ) ) . '' + ); + ?> +

+
+

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 literal 0 HcmV?d00001 diff --git a/packages/woocommerce-germanized-dhl/assets/js/admin-deutsche-post-label.js b/packages/woocommerce-germanized-dhl/assets/js/admin-deutsche-post-label.js new file mode 100644 index 000000000..2bfd715a3 --- /dev/null +++ b/packages/woocommerce-germanized-dhl/assets/js/admin-deutsche-post-label.js @@ -0,0 +1,110 @@ +window.germanized = window.germanized || {}; +window.germanized.admin = window.germanized.admin || {}; + +( function( $, admin ) { + + /** + * Core + */ + admin.dhl_post_label = { + + params: {}, + + init: function () { + var self = admin.dhl_post_label; + self.params = wc_gzd_admin_deutsche_post_label_params; + + $( document ).on( 'change', '#wc-gzd-shipment-label-admin-fields-deutsche_post #product_id, #wc-gzd-shipment-label-admin-fields-deutsche_post #wc-gzd-shipment-label-wrapper-additional-services :input', self.onRefreshPreview ); + }, + + getSelectedAdditionalServices: function() { + var selectedIds = $( "#wc-gzd-shipment-label-wrapper-additional-services :input:checked" ).map( function() { + return $( this ).attr( 'name' ).replace( 'service_', '' ); + }).get(); + + return selectedIds; + }, + + onRefreshPreview: function() { + var self = admin.dhl_post_label, + backbone = germanized.admin.shipment_label_backbone.backbone, + params = {}, + $wrapper = $( '.wc-gzd-shipment-create-label' ); + + params['security'] = self.params.refresh_label_preview_nonce; + params['product_id'] = self.getProductId(); + params['selected_services'] = self.getSelectedAdditionalServices(); + params['action'] = 'woocommerce_gzd_dhl_refresh_deutsche_post_label_preview'; + + backbone.doAjax( params, $wrapper, self.onPreviewSuccess ); + }, + + onPreviewSuccess: function( data ) { + var self = admin.dhl_post_label, + $wrapper = $( '.wc-gzd-dhl-im-product-data .col-preview' ), + $img_wrapper = $( '.wc-gzd-dhl-im-product-data' ).find( '.image-preview' ); + + if ( data.is_wp_int ) { + $wrapper.parents( '.wc-gzd-shipment-create-label' ).find( '.page_format_field' ).hide(); + } else { + $wrapper.parents( '.wc-gzd-shipment-create-label' ).find( '.page_format_field' ).show(); + } + + if ( data.preview_url ) { + $wrapper.block({ + message: null, + overlayCSS: { + background: '#fff', + opacity: 0.6 + } + }); + + if ( $img_wrapper.find( '.stamp-preview' ).length <= 0 ) { + $img_wrapper.append( '' ); + } + + self.replaceProductData( data.preview_data ); + + $img_wrapper.find( '.stamp-preview' ).attr('src', data.preview_url ).load( function() { + $wrapper.unblock(); + $( this ).show(); + }); + } else { + $img_wrapper.html( '' ); + } + }, + + refreshProductData: function() { + var self = admin.dhl_post_label; + + self.onRefreshPreview(); + }, + + getProductId: function() { + return $( '#wc-gzd-shipment-label-admin-fields-deutsche_post #product_id' ).val(); + }, + + replaceProductData: function( productData ) { + var self = admin.dhl_post_label, + $wrapper = $( '.wc-gzd-shipment-create-label' ).find( '.wc-gzd-dhl-im-product-data' ); + + $wrapper.find( '.data-placeholder' ).html( '' ); + + $wrapper.find( '.data-placeholder' ).each( function() { + var replaceKey = $( this ).data( 'replace' ); + + if ( productData.hasOwnProperty( replaceKey ) ) { + $( this ).html( productData[ replaceKey ] ); + $( this ).show(); + } else { + $( this ).hide(); + } + } ); + } + }; + + $( document ).ready( function() { + germanized.admin.dhl_post_label.init(); + }); + +})( jQuery, window.germanized.admin ); \ No newline at end of file diff --git a/packages/woocommerce-germanized-dhl/assets/js/admin-deutsche-post-label.min.js b/packages/woocommerce-germanized-dhl/assets/js/admin-deutsche-post-label.min.js new file mode 100644 index 000000000..9a979c4b6 --- /dev/null +++ b/packages/woocommerce-germanized-dhl/assets/js/admin-deutsche-post-label.min.js @@ -0,0 +1 @@ +window.germanized=window.germanized||{},window.germanized.admin=window.germanized.admin||{},function(d,n){n.dhl_post_label={params:{},init:function(){var e=n.dhl_post_label;e.params=wc_gzd_admin_deutsche_post_label_params,d(document).on("change","#wc-gzd-shipment-label-admin-fields-deutsche_post #product_id, #wc-gzd-shipment-label-admin-fields-deutsche_post #wc-gzd-shipment-label-wrapper-additional-services :input",e.onRefreshPreview)},getSelectedAdditionalServices:function(){return d("#wc-gzd-shipment-label-wrapper-additional-services :input:checked").map(function(){return d(this).attr("name").replace("service_","")}).get()},onRefreshPreview:function(){var e=n.dhl_post_label,a=germanized.admin.shipment_label_backbone.backbone,i={},t=d(".wc-gzd-shipment-create-label");i.security=e.params.refresh_label_preview_nonce,i.product_id=e.getProductId(),i.selected_services=e.getSelectedAdditionalServices(),i.action="woocommerce_gzd_dhl_refresh_deutsche_post_label_preview",a.doAjax(i,t,e.onPreviewSuccess)},onPreviewSuccess:function(e){var a=n.dhl_post_label,i=d(".wc-gzd-dhl-im-product-data .col-preview"),t=d(".wc-gzd-dhl-im-product-data").find(".image-preview");e.is_wp_int?i.parents(".wc-gzd-shipment-create-label").find(".page_format_field").hide():i.parents(".wc-gzd-shipment-create-label").find(".page_format_field").show(),e.preview_url?(i.block({message:null,overlayCSS:{background:"#fff",opacity:.6}}),t.find(".stamp-preview").length<=0&&t.append(''),a.replaceProductData(e.preview_data),t.find(".stamp-preview").attr("src",e.preview_url).load(function(){i.unblock(),d(this).show()})):t.html("")},refreshProductData:function(){n.dhl_post_label.onRefreshPreview()},getProductId:function(){return d("#wc-gzd-shipment-label-admin-fields-deutsche_post #product_id").val()},replaceProductData:function(a){n.dhl_post_label;var e=d(".wc-gzd-shipment-create-label").find(".wc-gzd-dhl-im-product-data");e.find(".data-placeholder").html(""),e.find(".data-placeholder").each(function(){var e=d(this).data("replace");a.hasOwnProperty(e)?(d(this).html(a[e]),d(this).show()):d(this).hide()})}},d(document).ready(function(){germanized.admin.dhl_post_label.init()})}(jQuery,window.germanized.admin); \ No newline at end of file diff --git a/packages/woocommerce-germanized-dhl/assets/js/admin-internetmarke.js b/packages/woocommerce-germanized-dhl/assets/js/admin-internetmarke.js new file mode 100644 index 000000000..cf3528bfc --- /dev/null +++ b/packages/woocommerce-germanized-dhl/assets/js/admin-internetmarke.js @@ -0,0 +1,266 @@ +window.germanized = window.germanized || {}; +window.germanized.admin = window.germanized.admin || {}; + +/* + * http://www.myersdaily.org/joseph/javascript/md5-text.html + */ +( function (global) { + + var md5cycle = function (x, k) { + var a = x[0], + b = x[1], + c = x[2], + d = x[3]; + + a = ff(a, b, c, d, k[0], 7, -680876936); + d = ff(d, a, b, c, k[1], 12, -389564586); + c = ff(c, d, a, b, k[2], 17, 606105819); + b = ff(b, c, d, a, k[3], 22, -1044525330); + a = ff(a, b, c, d, k[4], 7, -176418897); + d = ff(d, a, b, c, k[5], 12, 1200080426); + c = ff(c, d, a, b, k[6], 17, -1473231341); + b = ff(b, c, d, a, k[7], 22, -45705983); + a = ff(a, b, c, d, k[8], 7, 1770035416); + d = ff(d, a, b, c, k[9], 12, -1958414417); + c = ff(c, d, a, b, k[10], 17, -42063); + b = ff(b, c, d, a, k[11], 22, -1990404162); + a = ff(a, b, c, d, k[12], 7, 1804603682); + d = ff(d, a, b, c, k[13], 12, -40341101); + c = ff(c, d, a, b, k[14], 17, -1502002290); + b = ff(b, c, d, a, k[15], 22, 1236535329); + + a = gg(a, b, c, d, k[1], 5, -165796510); + d = gg(d, a, b, c, k[6], 9, -1069501632); + c = gg(c, d, a, b, k[11], 14, 643717713); + b = gg(b, c, d, a, k[0], 20, -373897302); + a = gg(a, b, c, d, k[5], 5, -701558691); + d = gg(d, a, b, c, k[10], 9, 38016083); + c = gg(c, d, a, b, k[15], 14, -660478335); + b = gg(b, c, d, a, k[4], 20, -405537848); + a = gg(a, b, c, d, k[9], 5, 568446438); + d = gg(d, a, b, c, k[14], 9, -1019803690); + c = gg(c, d, a, b, k[3], 14, -187363961); + b = gg(b, c, d, a, k[8], 20, 1163531501); + a = gg(a, b, c, d, k[13], 5, -1444681467); + d = gg(d, a, b, c, k[2], 9, -51403784); + c = gg(c, d, a, b, k[7], 14, 1735328473); + b = gg(b, c, d, a, k[12], 20, -1926607734); + + a = hh(a, b, c, d, k[5], 4, -378558); + d = hh(d, a, b, c, k[8], 11, -2022574463); + c = hh(c, d, a, b, k[11], 16, 1839030562); + b = hh(b, c, d, a, k[14], 23, -35309556); + a = hh(a, b, c, d, k[1], 4, -1530992060); + d = hh(d, a, b, c, k[4], 11, 1272893353); + c = hh(c, d, a, b, k[7], 16, -155497632); + b = hh(b, c, d, a, k[10], 23, -1094730640); + a = hh(a, b, c, d, k[13], 4, 681279174); + d = hh(d, a, b, c, k[0], 11, -358537222); + c = hh(c, d, a, b, k[3], 16, -722521979); + b = hh(b, c, d, a, k[6], 23, 76029189); + a = hh(a, b, c, d, k[9], 4, -640364487); + d = hh(d, a, b, c, k[12], 11, -421815835); + c = hh(c, d, a, b, k[15], 16, 530742520); + b = hh(b, c, d, a, k[2], 23, -995338651); + + a = ii(a, b, c, d, k[0], 6, -198630844); + d = ii(d, a, b, c, k[7], 10, 1126891415); + c = ii(c, d, a, b, k[14], 15, -1416354905); + b = ii(b, c, d, a, k[5], 21, -57434055); + a = ii(a, b, c, d, k[12], 6, 1700485571); + d = ii(d, a, b, c, k[3], 10, -1894986606); + c = ii(c, d, a, b, k[10], 15, -1051523); + b = ii(b, c, d, a, k[1], 21, -2054922799); + a = ii(a, b, c, d, k[8], 6, 1873313359); + d = ii(d, a, b, c, k[15], 10, -30611744); + c = ii(c, d, a, b, k[6], 15, -1560198380); + b = ii(b, c, d, a, k[13], 21, 1309151649); + a = ii(a, b, c, d, k[4], 6, -145523070); + d = ii(d, a, b, c, k[11], 10, -1120210379); + c = ii(c, d, a, b, k[2], 15, 718787259); + b = ii(b, c, d, a, k[9], 21, -343485551); + + x[0] = add32(a, x[0]); + x[1] = add32(b, x[1]); + x[2] = add32(c, x[2]); + x[3] = add32(d, x[3]); + + } + + var cmn = function (q, a, b, x, s, t) { + a = add32(add32(a, q), add32(x, t)); + return add32((a << s) | (a >>> (32 - s)), b); + } + + var ff = function (a, b, c, d, x, s, t) { + return cmn((b & c) | ((~b) & d), a, b, x, s, t); + } + + var gg = function (a, b, c, d, x, s, t) { + return cmn((b & d) | (c & (~d)), a, b, x, s, t); + } + + var hh = function (a, b, c, d, x, s, t) { + return cmn(b ^ c ^ d, a, b, x, s, t); + } + + var ii = function (a, b, c, d, x, s, t) { + return cmn(c ^ (b | (~d)), a, b, x, s, t); + } + + var md51 = function (s) { + var txt = '', + n = s.length, + state = [1732584193, -271733879, -1732584194, 271733878], + i; + for (i = 64; i <= s.length; i += 64) { + md5cycle(state, md5blk(s.substring(i - 64, i))); + } + s = s.substring(i - 64); + var tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + for (i = 0; i < s.length; i++) + tail[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3); + tail[i >> 2] |= 0x80 << ((i % 4) << 3); + if (i > 55) { + md5cycle(state, tail); + for (i = 0; i < 16; i++) tail[i] = 0; + } + tail[14] = n * 8; + md5cycle(state, tail); + return state; + } + + /* there needs to be support for Unicode here, + * unless we pretend that we can redefine the MD-5 + * algorithm for multi-byte characters (perhaps + * by adding every four 16-bit characters and + * shortening the sum to 32 bits). Otherwise + * I suggest performing MD-5 as if every character + * was two bytes--e.g., 0040 0025 = @%--but then + * how will an ordinary MD-5 sum be matched? + * There is no way to standardize text to something + * like UTF-8 before transformation; speed cost is + * utterly prohibitive. The JavaScript standard + * itself needs to look at this: it should start + * providing access to strings as preformed UTF-8 + * 8-bit unsigned value arrays. + */ + var md5blk = function (s) { /* I figured global was faster. */ + var md5blks = [], + i; /* Andy King said do it this way. */ + for (i = 0; i < 64; i += 4) { + md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << 24); + } + return md5blks; + } + + var hex_chr = '0123456789abcdef'.split(''); + + var rhex = function (n) { + var s = '', + j = 0; + for (; j < 4; j++) + s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] + hex_chr[(n >> (j * 8)) & 0x0F]; + return s; + } + + var hex = function (x) { + for (var i = 0; i < x.length; i++) + x[i] = rhex(x[i]); + return x.join(''); + } + + var md5 = global.md5 = function (s) { + return hex(md51(s)); + } + + /* this function is much faster, + so if possible we use it. Some IEs + are the only ones I know of that + need the idiotic second function, + generated by an if clause. */ + + var add32 = function (a, b) { + return (a + b) & 0xFFFFFFFF; + } + + if (md5('hello') != '5d41402abc4b2a76b9719d911017c592') { + var add32 = function (x, y) { + var lsw = (x & 0xFFFF) + (y & 0xFFFF), + msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); + } + } +})(window); + +( function( $, admin, window ) { + + /** + * Core + */ + admin.dhl_internetmarke = { + + params: {}, + + init: function () { + var self = admin.dhl_internetmarke; + + $( document ).on( 'click', '#woocommerce_gzd_dhl_im_portokasse_charge', self.onCharge ); + }, + + onCharge: function() { + var $button = $( this ), + data = $button.data(), + amount = $( '#woocommerce_gzd_dhl_im_portokasse_charge_amount' ).val(); + + $form = $( '
' ).appendTo( 'body' ); + + $.each( data, function( index, value ) { + $form.append( '' ); + } ); + + var balance = parseInt( ( parseFloat( amount.replace( ',', '.') ).toFixed( 2 ) * 100 ).toFixed() ); + var wallet = parseInt( data['wallet'] ); + + /** + * Set min amount. + */ + if ( balance < 1000 || Number.isNaN( balance ) ) { + balance = 1000; + } + + var date = new Date(); + var timestamp = + ('0' + date.getDate()).slice(-2) + + ('0' + (date.getMonth() + 1)).slice(-2) + + date.getFullYear().toString() + + '-' + + ('0' + date.getHours()).slice(-2) + + ('0' + date.getMinutes()).slice(-2) + + ('0' + date.getSeconds()).slice(-2); + + var concat = [ + data['partner_id'], + timestamp, + data['success_url'], + data['cancel_url'], + data['user_token'], + wallet + balance, + data['schluessel_dpwn_partner'] + ].join( '::' ); + + $form.append( '' ); + $form.append( '' ); + $form.append( '' ); + + $form.submit(); + + return false; + } + }; + + $( document ).ready( function() { + germanized.admin.dhl_internetmarke.init(); + }); + +})( jQuery, window.germanized.admin, window ); \ No newline at end of file diff --git a/packages/woocommerce-germanized-dhl/assets/js/admin-internetmarke.min.js b/packages/woocommerce-germanized-dhl/assets/js/admin-internetmarke.min.js new file mode 100644 index 000000000..ff0186a70 --- /dev/null +++ b/packages/woocommerce-germanized-dhl/assets/js/admin-internetmarke.min.js @@ -0,0 +1 @@ +window.germanized=window.germanized||{},window.germanized.admin=window.germanized.admin||{},function(e){var a=function(e,n){var r=e[0],t=e[1],o=e[2],a=e[3],r=i(r,t,o,a,n[0],7,-680876936),a=i(a,r,t,o,n[1],12,-389564586),o=i(o,a,r,t,n[2],17,606105819),t=i(t,o,a,r,n[3],22,-1044525330);r=i(r,t,o,a,n[4],7,-176418897),a=i(a,r,t,o,n[5],12,1200080426),o=i(o,a,r,t,n[6],17,-1473231341),t=i(t,o,a,r,n[7],22,-45705983),r=i(r,t,o,a,n[8],7,1770035416),a=i(a,r,t,o,n[9],12,-1958414417),o=i(o,a,r,t,n[10],17,-42063),t=i(t,o,a,r,n[11],22,-1990404162),r=i(r,t,o,a,n[12],7,1804603682),a=i(a,r,t,o,n[13],12,-40341101),o=i(o,a,r,t,n[14],17,-1502002290),t=i(t,o,a,r,n[15],22,1236535329),r=u(r,t,o,a,n[1],5,-165796510),a=u(a,r,t,o,n[6],9,-1069501632),o=u(o,a,r,t,n[11],14,643717713),t=u(t,o,a,r,n[0],20,-373897302),r=u(r,t,o,a,n[5],5,-701558691),a=u(a,r,t,o,n[10],9,38016083),o=u(o,a,r,t,n[15],14,-660478335),t=u(t,o,a,r,n[4],20,-405537848),r=u(r,t,o,a,n[9],5,568446438),a=u(a,r,t,o,n[14],9,-1019803690),o=u(o,a,r,t,n[3],14,-187363961),t=u(t,o,a,r,n[8],20,1163531501),r=u(r,t,o,a,n[13],5,-1444681467),a=u(a,r,t,o,n[2],9,-51403784),o=u(o,a,r,t,n[7],14,1735328473),t=u(t,o,a,r,n[12],20,-1926607734),r=c(r,t,o,a,n[5],4,-378558),a=c(a,r,t,o,n[8],11,-2022574463),o=c(o,a,r,t,n[11],16,1839030562),t=c(t,o,a,r,n[14],23,-35309556),r=c(r,t,o,a,n[1],4,-1530992060),a=c(a,r,t,o,n[4],11,1272893353),o=c(o,a,r,t,n[7],16,-155497632),t=c(t,o,a,r,n[10],23,-1094730640),r=c(r,t,o,a,n[13],4,681279174),a=c(a,r,t,o,n[0],11,-358537222),o=c(o,a,r,t,n[3],16,-722521979),t=c(t,o,a,r,n[6],23,76029189),r=c(r,t,o,a,n[9],4,-640364487),a=c(a,r,t,o,n[12],11,-421815835),o=c(o,a,r,t,n[15],16,530742520),t=c(t,o,a,r,n[2],23,-995338651),r=m(r,t,o,a,n[0],6,-198630844),a=m(a,r,t,o,n[7],10,1126891415),o=m(o,a,r,t,n[14],15,-1416354905),t=m(t,o,a,r,n[5],21,-57434055),r=m(r,t,o,a,n[12],6,1700485571),a=m(a,r,t,o,n[3],10,-1894986606),o=m(o,a,r,t,n[10],15,-1051523),t=m(t,o,a,r,n[1],21,-2054922799),r=m(r,t,o,a,n[8],6,1873313359),a=m(a,r,t,o,n[15],10,-30611744),o=m(o,a,r,t,n[6],15,-1560198380),t=m(t,o,a,r,n[13],21,1309151649),r=m(r,t,o,a,n[4],6,-145523070),a=m(a,r,t,o,n[11],10,-1120210379),o=m(o,a,r,t,n[2],15,718787259),t=m(t,o,a,r,n[9],21,-343485551),e[0]=l(r,e[0]),e[1]=l(t,e[1]),e[2]=l(o,e[2]),e[3]=l(a,e[3])},d=function(e,n,r,t,o,a){return n=l(l(n,e),l(t,a)),l(n<>>32-o,r)},i=function(e,n,r,t,o,a,i){return d(n&r|~n&t,e,n,o,a,i)},u=function(e,n,r,t,o,a,i){return d(n&t|r&~t,e,n,o,a,i)},c=function(e,n,r,t,o,a,i){return d(n^r^t,e,n,o,a,i)},m=function(e,n,r,t,o,a,i){return d(r^(n|~t),e,n,o,a,i)},t="0123456789abcdef".split(""),n=function(e){for(var n=0;n>8*r+4&15]+t[e>>8*r&15];return n}(e[n]);return e.join("")},e=e.md5=function(e){return n(function(e){for(var n=e.length,r=[1732584193,-271733879,-1732584194,271733878],t=64;t<=e.length;t+=64)a(r,function(e){for(var n=[],r,r=0;r<64;r+=4)n[r>>2]=e.charCodeAt(r)+(e.charCodeAt(r+1)<<8)+(e.charCodeAt(r+2)<<16)+(e.charCodeAt(r+3)<<24);return n}(e.substring(t-64,t)));e=e.substring(t-64);var o=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];for(t=0;t>2]|=e.charCodeAt(t)<<(t%4<<3);if(o[t>>2]|=128<<(t%4<<3),55>16)+(n>>16)+(r>>16)<<16|65535&r})}(window),function(o,n,a){n.dhl_internetmarke={params:{},init:function(){var e=n.dhl_internetmarke;o(document).on("click","#woocommerce_gzd_dhl_im_portokasse_charge",e.onCharge)},onCharge:function(){var e=o(this),n=e.data(),r=o("#woocommerce_gzd_dhl_im_portokasse_charge_amount").val();$form=o('
').appendTo("body"),o.each(n,function(e,n){$form.append('')});var t=parseInt((100*parseFloat(r.replace(",",".")).toFixed(2)).toFixed()),e=parseInt(n.wallet);(t<1e3||Number.isNaN(t))&&(t=1e3);r=new Date,r=("0"+r.getDate()).slice(-2)+("0"+(r.getMonth()+1)).slice(-2)+r.getFullYear().toString()+"-"+("0"+r.getHours()).slice(-2)+("0"+r.getMinutes()).slice(-2)+("0"+r.getSeconds()).slice(-2),n=[n.partner_id,r,n.success_url,n.cancel_url,n.user_token,e+t,n.schluessel_dpwn_partner].join("::");return $form.append(''),$form.append(''),$form.append(''),$form.submit(),!1}},o(document).ready(function(){germanized.admin.dhl_internetmarke.init()})}(jQuery,window.germanized.admin,window); \ No newline at end of file diff --git a/packages/woocommerce-germanized-dhl/assets/js/parcel-finder.js b/packages/woocommerce-germanized-dhl/assets/js/parcel-finder.js new file mode 100644 index 000000000..d9c4f5e7b --- /dev/null +++ b/packages/woocommerce-germanized-dhl/assets/js/parcel-finder.js @@ -0,0 +1,300 @@ +window.germanized = window.germanized || {}; +window.germanized.dhl_parcel_finder = window.germanized.dhl_parcel_finder || {}; + +( function( $, germanized ) { + + /** + * Core + */ + germanized.dhl_parcel_finder = { + + params: {}, + parcelShops: [], + wrapper: '', + + init: function () { + var self = germanized.dhl_parcel_finder; + self.params = wc_gzd_dhl_parcel_finder_params; + self.wrapper = self.params.wrapper; + + $( document ) + .on( 'click', '.gzd-dhl-parcel-shop-modal', self.openModal ) + .on( 'click', '#dhl-parcel-finder-wrapper .dhl-parcel-finder-close', self.closeModal ) + .on( 'submit', '#dhl-parcel-finder-wrapper #dhl-parcel-finder-form', self.onSubmit ) + .on( 'click', '#dhl-parcel-finder-wrapper .dhl-retry-search', self.onSubmit ) + .on( 'click', '#dhl-parcel-finder-wrapper .dhl-parcelshop-select-btn', self.onSelectShop ); + + $( document.body ).bind( 'woocommerce_gzd_dhl_location_available_pickup_types_changed', self.onChangeAvailablePickupTypes ); + }, + + onChangeAvailablePickupTypes: function() { + var self = germanized.dhl_parcel_finder, + loc = germanized.dhl_parcel_locator, + $modal = self.getModal(), + method = loc.getShippingMethod(), + methodData = loc.getShippingMethodData( method ); + + if ( methodData ) { + + $modal.find( '.finder-pickup-type' ).addClass( 'hidden' ); + + $.each( methodData.supports, function( i, pickupType ) { + var $type = $modal.find( '.finder-pickup-type[data-pickup_type="' + pickupType + '"]' ); + + $type.find( 'input[type=checkbox]' ).prop( 'checked', true ); + $type.removeClass( 'hidden' ); + }); + } + }, + + openModal: function() { + var self = germanized.dhl_parcel_finder, + $modal = self.getModal(); + + var country = $( self.wrapper + ' #shipping_country' ).val().length > 0 ? $( self.wrapper + ' #shipping_country' ).val() : $( self.wrapper + ' #billing_country' ).val(); + $modal.find( '#dhl-parcelfinder-country').val( country ); + + var postcode = $( self.wrapper + ' #shipping_postcode' ).val().length > 0 ? $( self.wrapper + ' #shipping_postcode' ).val() : $( self.wrapper + ' #billing_postcode' ).val(); + $modal.find( '#dhl-parcelfinder-postcode' ).val( postcode ); + + var city = $( self.wrapper + ' #shipping_city' ).val().length > 0 ? $( self.wrapper + ' #shipping_city' ).val() : $( self.wrapper + ' #billing_city' ).val(); + $modal.find( '#dhl-parcelfinder-city' ).val( city ); + + $modal.addClass( 'open' ); + $modal.find( '#dhl-parcel-finder-form' ).submit(); + + return false; + }, + + closeModal: function() { + var self = germanized.dhl_parcel_finder; + self.getModal().removeClass( 'open' ); + + return false; + }, + + getModal: function() { + return $( '#dhl-parcel-finder-wrapper' ); + }, + + doAjax: function( params, $wrapper, cSuccess, cError ) { + var self = germanized.dhl_parcel_finder; + + cSuccess = cSuccess || self.onAjaxSuccess; + cError = cError || self.onAjaxError; + + if ( ! params.hasOwnProperty( 'security' ) ) { + params['security'] = self.params.parcel_finder_nonce; + } + + $wrapper.find( '#dhl-parcel-finder-map' ).block({ + message: null, + overlayCSS: { + background: '#fff', + opacity: 0.6 + } + }); + + $wrapper.find( '.notice-wrapper' ).empty(); + + $.ajax({ + type: "POST", + url: self.params.ajax_url, + data: params, + success: function( data ) { + if ( data.success ) { + $wrapper.find( '#dhl-parcel-finder-map' ).unblock(); + cSuccess.apply( $wrapper, [ data ] ); + } else { + cError.apply( $wrapper, [ data ] ); + $wrapper.find( '#dhl-parcel-finder-map' ).unblock(); + + if ( data.hasOwnProperty( 'message' ) ) { + self.addNotice( data.message, 'error', $wrapper ); + } else if( data.hasOwnProperty( 'messages' ) ) { + $.each( data.messages, function( i, message ) { + self.addNotice( message, 'error', $wrapper ); + }); + } + } + }, + error: function( data ) {}, + dataType: 'json' + }); + }, + + onAjaxSuccess: function( data ) {}, + + onAjaxError: function( data ) {}, + + getFormData: function( $form ) { + var data = {}; + + $.each( $form.serializeArray(), function( index, item ) { + if ( item.name.indexOf( '[]' ) !== -1 ) { + item.name = item.name.replace( '[]', '' ); + data[ item.name ] = $.makeArray( data[ item.name ] ); + data[ item.name ].push( item.value ); + } else { + data[ item.name ] = item.value; + } + }); + + return data; + }, + + onSubmit: function( e ) { + var self = germanized.dhl_parcel_finder, + loc = germanized.dhl_parcel_locator, + $modal = self.getModal(), + $content = $modal.find( '#dhl-parcel-finder' ), + $form = $content.find( 'form' ), + params = self.getFormData( $form ); + + params['action'] = 'woocommerce_gzd_dhl_parcelfinder_search'; + params['is_checkout'] = loc.isCheckout() ? 'yes' : 'no'; + + self.doAjax( params, $content, self.onSubmitSuccess ); + + return false; + }, + + onSubmitSuccess: function( data ) { + var self = germanized.dhl_parcel_finder; + + if ( data.parcel_shops ) { + self.parcelShops = data.parcel_shops; + + if ( typeof google === 'object' && typeof google.maps === 'object' ) { + self.updateMap(); + } else { + self.loadMapsAPI(); + } + } + }, + + loadMapsAPI: function() { + var self = germanized.dhl_parcel_finder; + + self.addScript( 'https://maps.googleapis.com/maps/api/js?key=' + self.params.api_key, self.updateMap ); + }, + + addScript: function( url, callback ) { + var script = document.createElement( 'script' ); + + if ( callback ) { + script.onload = callback; + } + + script.type = 'text/javascript'; + script.src = url; + document.body.appendChild( script ); + }, + + updateMap: function() { + var self = germanized.dhl_parcel_finder, + parcelShops = self.parcelShops; + + var uluru = { + lat: parcelShops[0].location.latitude, + lng: parcelShops[0].location.longitude + }; + + var map = new google.maps.Map( document.getElementById('dhl-parcel-finder-map' ), { + zoom: 13, + center: uluru + }); + + var infoWinArray = []; + + $.each( parcelShops, function( key, value ) { + + var uluru = { + lat: value.location.latitude, + lng: value.location.longitude + }; + + var markerIcon = self.params.packstation_icon, + shopLabel = self.params.i18n.packstation; + + switch ( value.gzd_type ) { + case 'parcelshop': + markerIcon = self.params.parcelshop_icon; + shopLabel = self.params.i18n.branch; + break; + case 'postoffice': + markerIcon = self.params.postoffice_icon; + shopLabel = self.params.i18n.branch; + break; + } + + var infowindow = new google.maps.InfoWindow({ + content: value.html_content, + maxWidth: 300 + }); + + infoWinArray.push( infowindow ); + + var marker = new google.maps.Marker({ + position : uluru, + map : map, + title : shopLabel, + animation: google.maps.Animation.DROP, + icon : markerIcon + }); + + marker.addListener('click', function() { + clearOverlays(); + infowindow.open( map, marker ); + }); + }); + + // Clear all info windows + function clearOverlays() { + for ( var i = 0; i < infoWinArray.length; i++ ) { + infoWinArray[i].close(); + } + } + }, + + onSelectShop: function() { + var self = germanized.dhl_parcel_finder, + parcelShopId = parseInt( $( this ).attr( 'id' ) ), + $addressType = $( self.wrapper + ' #shipping_address_type' ); + + $.each( self.parcelShops, function( key, value ) { + if ( parseInt( value.id ) === parcelShopId ) { + + var isPackstation = 'packstation' === value.gzd_type; + + $( self.wrapper + ' #shipping_first_name' ).val( $( self.wrapper + ' #shipping_first_name' ).val().length > 0 ? $( self.wrapper + ' #shipping_first_name' ).val() : $( self.wrapper + ' #billing_first_name' ).val() ); + $( self.wrapper + ' #shipping_last_name' ).val( $( self.wrapper + ' #shipping_last_name' ).val().length > 0 ? $( self.wrapper + ' #shipping_last_name' ).val() : $( self.wrapper + ' #billing_last_name' ).val() ); + + $( self.wrapper + ' #shipping_address_1' ).val( value.gzd_name ); + $( self.wrapper + ' #shipping_address_2' ).val( '' ); + $( self.wrapper + ' #shipping_postcode' ).val( value.address.zip ); + $( self.wrapper + ' #shipping_city' ).val( value.address.city ); + + $addressType.val( 'dhl' ).trigger( 'change' ); + + self.closeModal(); + + if ( isPackstation && $( self.wrapper + ' #shipping_dhl_postnumber' ).val() === '' ) { + $( self.wrapper + ' #shipping_dhl_postnumber' ).focus(); + } + + return true; + } + }); + }, + + addNotice: function( message, noticeType, $wrapper ) { + $wrapper.find( '.notice-wrapper' ).append( '

' + message + '

' ); + } + }; + + $( document ).ready( function() { + germanized.dhl_parcel_finder.init(); + }); + +})( jQuery, window.germanized ); diff --git a/packages/woocommerce-germanized-dhl/assets/js/parcel-finder.min.js b/packages/woocommerce-germanized-dhl/assets/js/parcel-finder.min.js new file mode 100644 index 000000000..153ef9380 --- /dev/null +++ b/packages/woocommerce-germanized-dhl/assets/js/parcel-finder.min.js @@ -0,0 +1 @@ +window.germanized=window.germanized||{},window.germanized.dhl_parcel_finder=window.germanized.dhl_parcel_finder||{},function(o,t){t.dhl_parcel_finder={params:{},parcelShops:[],wrapper:"",init:function(){var e=t.dhl_parcel_finder;e.params=wc_gzd_dhl_parcel_finder_params,e.wrapper=e.params.wrapper,o(document).on("click",".gzd-dhl-parcel-shop-modal",e.openModal).on("click","#dhl-parcel-finder-wrapper .dhl-parcel-finder-close",e.closeModal).on("submit","#dhl-parcel-finder-wrapper #dhl-parcel-finder-form",e.onSubmit).on("click","#dhl-parcel-finder-wrapper .dhl-retry-search",e.onSubmit).on("click","#dhl-parcel-finder-wrapper .dhl-parcelshop-select-btn",e.onSelectShop),o(document.body).bind("woocommerce_gzd_dhl_location_available_pickup_types_changed",e.onChangeAvailablePickupTypes)},onChangeAvailablePickupTypes:function(){var e=t.dhl_parcel_finder,a=t.dhl_parcel_locator,r=e.getModal(),e=a.getShippingMethod(),a=a.getShippingMethodData(e);a&&(r.find(".finder-pickup-type").addClass("hidden"),o.each(a.supports,function(e,a){a=r.find('.finder-pickup-type[data-pickup_type="'+a+'"]');a.find("input[type=checkbox]").prop("checked",!0),a.removeClass("hidden")}))},openModal:function(){var e=t.dhl_parcel_finder,a=e.getModal(),r=(0

'+e+"

")}},o(document).ready(function(){t.dhl_parcel_finder.init()})}(jQuery,window.germanized); \ No newline at end of file diff --git a/packages/woocommerce-germanized-dhl/assets/js/parcel-locator.js b/packages/woocommerce-germanized-dhl/assets/js/parcel-locator.js new file mode 100644 index 000000000..db31b0007 --- /dev/null +++ b/packages/woocommerce-germanized-dhl/assets/js/parcel-locator.js @@ -0,0 +1,420 @@ + +window.germanized = window.germanized || {}; +window.germanized.dhl_parcel_locator = window.germanized.dhl_parcel_locator || {}; + +( function( $, germanized ) { + + /** + * Core + */ + germanized.dhl_parcel_locator = { + + params: {}, + parcelShops: [], + wrapper: '', + + init: function () { + var self = germanized.dhl_parcel_locator; + self.params = wc_gzd_dhl_parcel_locator_params; + self.wrapper = self.params.wrapper; + + $( document ) + .on( 'change.dhl', self.wrapper + ' #shipping_address_type', self.refreshAddressType ) + .on( 'change.dhl', self.wrapper + ' #shipping_address_1', self.onChangeAddress ) + .on( 'change.dhl', self.wrapper + ' #ship-to-different-address-checkbox', self.onChangeShipping ) + .on( 'change.dhl', self.wrapper + ' #shipping_country', self.refreshAvailability ); + + $( document.body ).on( 'payment_method_selected', self.triggerCheckoutRefresh ); + $( document.body ).on( 'updated_checkout', self.afterRefreshCheckout ); + + self.refreshAvailability(); + self.refreshAddressType(); + }, + + triggerCheckoutRefresh: function() { + $( document.body ).trigger( 'update_checkout' ); + }, + + isCheckout: function() { + var self = germanized.dhl_parcel_locator; + + return self.params.is_checkout; + }, + + afterRefreshCheckout: function() { + var self = germanized.dhl_parcel_locator; + + var params = { + 'security': self.params.parcel_locator_data_nonce, + 'action' : 'woocommerce_gzd_dhl_parcel_locator_refresh_shipping_data' + }; + + $.ajax({ + type: "POST", + url: self.params.ajax_url, + data: params, + success: function( data ) { + // Update shipping method data from session + self.params['methods'] = data.methods; + self.refreshAvailability(); + }, + error: function( data ) { + self.refreshAvailability(); + }, + dataType: 'json' + }); + }, + + refreshAvailability: function() { + var self = germanized.dhl_parcel_locator, + shippingMethod = self.getShippingMethod(), + methodData = self.getShippingMethodData( shippingMethod ); + + if ( ! self.isAvailable() ) { + $( self.wrapper + ' #shipping_address_type' ).val( 'regular' ).trigger( 'change' ); + $( self.wrapper + ' #shipping_address_type_field' ).hide(); + } else { + var $typeField = $( self.wrapper + ' #shipping_address_type' ); + var selected = $typeField.val(); + + if ( self.isCheckout() ) { + $typeField.html( '' ); + + if ( methodData ) { + $.each( methodData.address_type_options, function( name, title ) { + $typeField.append( $( '"),$quantity.data("max-quantity-"+t,i.max_quantity)}),n(".wc-backbone-modal-content article").unblock(),n(document.body).on("change","input#wc-gzd-shipment-add-items-quantity",function(){var t=$select.val(),i=n(this).val();$quantity.data("max-quantity-"+t)&&(t=$quantity.data("max-quantity-"+t)) 0 ) { + + var actionData = self.params.bulk_actions[ action ]; + + $( '.bulk-action-wrapper' ).find( '.bulk-title' ).text( actionData['title'] ); + $( '#posts-filter' ).addClass( 'bulk-action-processing' ); + $( '#posts-filter' ).find( '.bulkactions button' ).prop( 'disabled', true ); + + // Handle bulk action processing + self.handleBulkAction( action, 1, ids, type ); + + return false; + } + }, + + handleBulkAction: function( action, step, ids, type ) { + var self = germanized.admin.shipments_table, + actionData = self.params.bulk_actions[ action ]; + + $.ajax( { + type: 'POST', + url: self.params.ajax_url, + data: { + action : 'woocommerce_gzd_shipments_bulk_action_handle', + bulk_action : action, + step : step, + type : type, + ids : ids, + security : actionData['nonce'] + }, + dataType: 'json', + success: function( response ) { + if ( response.success ) { + + if ( 'done' === response.data.step ) { + $( '.bulk-action-wrapper' ).find( '.woocommerce-shimpents-bulk-progress' ).val( response.data.percentage ); + + window.location = response.data.url; + + setTimeout( function() { + $( '#posts-filter' ).removeClass( 'bulk-action-processing' ); + $( '#posts-filter' ).find( '.bulkactions button' ).prop( 'disabled', false ); + }, 2000 ); + } else { + $( '.bulk-action-wrapper' ).find( '.woocommerce-shimpents-bulk-progress' ).val( response.data.percentage ); + self.handleBulkAction( action, parseInt( response.data.step, 10 ), response.data.ids, response.data.type ); + } + } + } + }).fail( function( response ) { + window.console.log( response ); + } ); + }, + + initTipTip: function() { + $( '.column-actions .wc-gzd-shipment-action-button' ).tipTip( { + 'fadeIn': 50, + 'fadeOut': 50, + 'delay': 200 + }); + }, + + initEnhanced: function() { + try { + $( document.body ) + .on( 'wc-enhanced-select-init', function() { + + // Ajax customer search boxes + $( ':input.wc-gzd-order-search' ).filter( ':not(.enhanced)' ).each( function() { + var select2_args = { + allowClear: $( this ).data( 'allow_clear' ) ? true : false, + placeholder: $( this ).data( 'placeholder' ), + minimumInputLength: $( this ).data( 'minimum_input_length' ) ? $( this ).data( 'minimum_input_length' ) : '1', + escapeMarkup: function( m ) { + return m; + }, + ajax: { + url: wc_gzd_admin_shipments_table_params.ajax_url, + dataType: 'json', + delay: 1000, + data: function( params ) { + return { + term: params.term, + action: 'woocommerce_gzd_json_search_orders', + security: wc_gzd_admin_shipments_table_params.search_orders_nonce, + exclude: $( this ).data( 'exclude' ) + }; + }, + processResults: function( data ) { + var terms = []; + if ( data ) { + $.each( data, function( id, text ) { + terms.push({ + id: id, + text: text + }); + }); + } + return { + results: terms + }; + }, + cache: true + } + }; + + $( this ).selectWoo( select2_args ).addClass( 'enhanced' ); + }); + + }); + + $( 'html' ).on( 'click', function( event ) { + if ( this === event.target ) { + $( ':input.wc-gzd-order-search' ).filter( '.select2-hidden-accessible' ).selectWoo( 'close' ); + } + } ); + } catch( err ) { + // If select2 failed (conflict?) log the error but don't stop other scripts breaking. + window.console.log( err ); + } + } + }; + + $( document ).ready( function() { + germanized.admin.shipments_table.init(); + }); + +})( jQuery, window.germanized.admin ); diff --git a/packages/woocommerce-germanized-shipments/assets/js/admin-shipments-table.min.js b/packages/woocommerce-germanized-shipments/assets/js/admin-shipments-table.min.js new file mode 100644 index 000000000..699ca3f2d --- /dev/null +++ b/packages/woocommerce-germanized-shipments/assets/js/admin-shipments-table.min.js @@ -0,0 +1 @@ +window.germanized=window.germanized||{},window.germanized.admin=window.germanized.admin||{},function(s){window.germanized.admin.shipments_table={params:{},init:function(){var n=germanized.admin.shipments_table;n.params=wc_gzd_admin_shipments_table_params,n.initEnhanced(),s(document).on("click","#doaction, #doaction2",n.onBulkSubmit).on("click",".wc-gzd-shipment-action-button-generate-label",n.onCreateLabel),s(document.body).on("init_tooltips",function(){n.initTipTip()}),n.initTipTip()},onCreateLabel:function(){germanized.admin.shipments_table;var n=s(this).parents("tr").find("th.check-column input").val();return s(this).parents("td").WCBackboneModal({template:"wc-gzd-modal-create-shipment-label-"+n}),!1},onBulkSubmit:function(){var n,t=germanized.admin.shipments_table,e=s(this).parents(".bulkactions").find("select[name^=action]").val(),a=s(this).parents("#posts-filter").find("input.shipment_type").val(),i=[];if(s("#posts-filter").find('input[name="shipment[]"]:checked').each(function(){i.push(s(this).val())}),t.params.bulk_actions.hasOwnProperty(e)&&0 0 ) { + return $shipment.data( 'shipment' ); + } + + return false; + }, + + block: function() { + var self = germanized.admin.shipments; + + self.$wrapper.block({ + message: null, + overlayCSS: { + background: '#fff', + opacity: 0.6 + } + }); + }, + + unblock: function() { + var self = germanized.admin.shipments; + + self.$wrapper.unblock(); + }, + + getData: function( additionalData ) { + var self = germanized.admin.shipments, + data = {}; + + additionalData = additionalData || {}; + + $.each( self.$wrapper.find( ':input[name]' ).serializeArray(), function( index, item ) { + if ( item.name.indexOf( '[]' ) !== -1 ) { + item.name = item.name.replace( '[]', '' ); + data[ item.name ] = $.makeArray( data[ item.name ] ); + data[ item.name ].push( item.value ); + } else { + data[ item.name ] = item.value; + } + }); + + $.extend( data, additionalData ); + + return data; + }, + + doAjax: function( params, cSuccess, cError ) { + var self = germanized.admin.shipments, + url = self.params.ajax_url, + $wrapper = self.$wrapper, + refreshFragments = true; + + $wrapper.find( '.notice-wrapper' ).empty(); + + cSuccess = cSuccess || self.onAjaxSuccess; + cError = cError || self.onAjaxError; + + if ( params.hasOwnProperty( 'refresh_fragments' ) ) { + refreshFragments = params['refresh_fragments']; + } + + if ( ! params.hasOwnProperty( 'security' ) ) { + params['security'] = self.params.edit_shipments_nonce; + } + + if ( ! params.hasOwnProperty( 'order_id' ) ) { + params['order_id'] = self.params.order_id; + } + + params = self.getData( params ); + + $.ajax({ + type: "POST", + url: url, + data: params, + success: function( data ) { + if ( data.success ) { + + active = self.getShipment( self.getActiveShipmentId() ); + current_packaging_id = false; + + if ( active ) { + current_packaging_id = active.getShipment().find( '.shipment-packaging-select' ).val(); + } + + if ( refreshFragments ) { + if ( data.fragments ) { + $.each( data.fragments, function ( key, value ) { + $( key ).replaceWith( value ); + $( key ).unblock(); + } ); + } + } + + cSuccess.apply( $wrapper, [ data ] ); + + if ( data.hasOwnProperty( 'order_needs_new_shipments' ) ) { + self.setNeedsShipments( data.order_needs_new_shipments ); + } + + if ( data.hasOwnProperty( 'order_needs_new_returns' ) ) { + self.setNeedsReturns( data.order_needs_new_returns ); + } + + var shipmentData = data.hasOwnProperty( 'shipments' ) ? data.shipments : {}; + + $.each( self.getShipments(), function( shipmentId, shipment ) { + + if ( shipmentData.hasOwnProperty( shipmentId ) ) { + shipment.setIsEditable( shipmentData[ shipmentId ].is_editable ); + shipment.setNeedsItems( shipmentData[ shipmentId ].needs_items ); + shipment.setWeight( shipmentData[ shipmentId ].weight ); + shipment.setLength( shipmentData[ shipmentId ].length ); + shipment.setWidth( shipmentData[ shipmentId ].width ); + shipment.setHeight( shipmentData[ shipmentId ].height ); + shipment.setTotalWeight( shipmentData[ shipmentId ].total_weight ); + + self.initShipment( shipmentId ); + } + }); + + if ( ( data.hasOwnProperty( 'needs_refresh' ) || data.hasOwnProperty( 'needs_packaging_refresh' ) ) && data.hasOwnProperty( 'shipment_id' ) ) { + self.initShipment( data.shipment_id ); + + if ( data.hasOwnProperty( 'needs_packaging_refresh' ) ) { + active = self.getShipment( self.getActiveShipmentId() ); + + if ( active ) { + // Refresh dimensions in case the packaging has changed + new_packaging_id = active.getShipment().find( '.shipment-packaging-select' ).val(); + + if ( new_packaging_id !== current_packaging_id ) { + self.getShipment( data.shipment_id ).refreshDimensions(); + } + } + } + } + } else { + cError.apply( $wrapper, [ data ] ); + self.unblock(); + + if ( data.hasOwnProperty( 'message' ) ) { + self.addNotice( data.message, 'error' ); + } else if( data.hasOwnProperty( 'messages' ) ) { + $.each( data.messages, function( i, message ) { + self.addNotice( message, 'error' ); + }); + } + } + }, + error: function( data ) { + cError.apply( $wrapper, [ data ] ); + self.unblock(); + }, + dataType: 'json' + }); + }, + + onAjaxError: function( data ) { + + }, + + onAjaxSuccess: function( data ) { + + }, + + onRemoveNotice: function() { + $( this ).parents( '.notice' ).slideUp( 150, function() { + $( this ).remove(); + }); + }, + + addNotice: function( message, noticeType ) { + var self = germanized.admin.shipments; + + self.$wrapper.find( '.notice-wrapper' ).append( '

' + message + '

' ); + }, + + getParams: function() { + var self = germanized.admin.shipments; + + return self.params; + }, + + onRemoveShipment: function() { + var self = germanized.admin.shipments, + $shipment = $( this ).parents( '.order-shipment' ), + id = $shipment.data( 'shipment' ); + + var answer = window.confirm( self.getParams().i18n_remove_shipment_notice ); + + if ( answer ) { + self.removeShipment( id ); + } + + return false; + }, + + removeShipment: function( shipment_id ) { + var self = germanized.admin.shipments; + + var params = { + 'action' : 'woocommerce_gzd_remove_shipment', + 'shipment_id': shipment_id + }; + + self.block(); + self.doAjax( params, self.onRemoveShipmentSuccess, self.onRemoveShipmentError ); + }, + + onRemoveShipmentSuccess: function( data ) { + var self = germanized.admin.shipments, + shipmentIds = Array.isArray( data['shipment_id'] ) ? data['shipment_id'] : [data['shipment_id']]; + + $.each( shipmentIds, function( i, shipmentId ) { + var $shipment = self.$wrapper.find( '#shipment-' + shipmentId ); + + if ( $shipment.length > 0 ) { + if ( $shipment.hasClass( 'active' ) ) { + $shipment.find( '.shipment-content-wrapper' ).slideUp( 300, function() { + $shipment.removeClass( 'active' ); + $shipment.remove(); + + self.initShipments(); + }); + } else { + $shipment.remove(); + } + } + }); + + self.initShipments(); + self.unblock(); + }, + + onRemoveShipmentError: function( data ) { + var self = germanized.admin.shipments; + + self.unblock(); + }, + + onAddShipment: function() { + var self = germanized.admin.shipments; + + self.addShipment(); + + return false; + }, + + addShipment: function() { + var self = germanized.admin.shipments; + + var params = { + 'action': 'woocommerce_gzd_add_shipment' + }; + + self.block(); + self.doAjax( params, self.onAddShipmentSuccess, self.onAddShipmentError ); + }, + + onAddShipmentSuccess: function( data ) { + var self = germanized.admin.shipments; + + if ( self.$wrapper.find( '.order-shipment.active' ).length > 0 ) { + self.$wrapper.find( '.order-shipment.active' ).find( '.shipment-content-wrapper' ).slideUp( 300, function() { + + self.$wrapper.find( '.order-shipment.active' ).removeClass( 'active' ); + self.appendNewShipment( data ); + + self.initShipments(); + + // Init tiptip + self.initTiptip(); + self.unblock(); + }); + } else { + self.appendNewShipment( data ); + self.initShipments(); + + // Init tiptip + self.initTiptip(); + self.unblock(); + } + }, + + appendNewShipment: function( data ) { + var self = germanized.admin.shipments; + + if ( 'simple' === data['new_shipment_type'] && self.$wrapper.find( '.panel-order-return-title' ).length > 0 ) { + self.$wrapper.find( '.panel-order-return-title' ).before( data.new_shipment ); + } else { + self.$wrapper.find( '#order-shipments-list' ).append( data.new_shipment ); + } + }, + + onAddShipmentError: function( data ) { + + }, + + onAddReturn: function() { + + $( this ).WCBackboneModal({ + template: 'wc-gzd-modal-add-shipment-return' + }); + + return false; + }, + + addReturn: function( items ) { + var self = germanized.admin.shipments; + + self.block(); + + var params = { + 'action' : 'woocommerce_gzd_add_return_shipment' + }; + + $.extend( params, items ); + + self.doAjax( params, self.onAddReturnSuccess, self.onAddReturnError ); + }, + + onAddReturnSuccess: function( data ) { + var self = germanized.admin.shipments; + + self.onAddShipmentSuccess( data ); + }, + + onAddReturnError: function( data ) { + var self = germanized.admin.shipments; + + self.onAddShipmentError( data ); + }, + + setNeedsSaving: function( needsSaving ) { + var self = germanized.admin.shipments, + shipmentId = self.getActiveShipmentId(), + $shipment = shipmentId ? self.getShipment( shipmentId ).getShipment() : false; + + if ( typeof needsSaving !== "boolean" ) { + needsSaving = true; + } + + self.needsSaving = needsSaving === true; + + if ( self.needsSaving ) { + self.$wrapper.find( '#order-shipments-save' ).show(); + } else { + self.$wrapper.find( '#order-shipments-save' ).hide(); + } + + if ( $shipment ) { + if ( self.needsSaving ) { + self.disableCreateLabel( $shipment ); + } else { + self.enableCreateLabel( $shipment ); + } + } + + if ( self.needsSaving ) { + self.disableCreateLabel( $shipment ); + } else { + self.enableCreateLabel( $shipment ); + } + + self.hideOrShowFooter(); + + $( document.body ).trigger( 'woocommerce_gzd_shipments_needs_saving', [ self.needsSaving, self.getActiveShipmentId() ] ); + + self.initTiptip(); + }, + + disableCreateLabel: function( $shipment ) { + var self = germanized.admin.shipments, + $button = $shipment.find( '.create-shipment-label' ); + + if ( $button.length > 0 ) { + $button.addClass( 'disabled button-disabled' ); + $button.prop( 'title', self.params.i18n_create_label_disabled ); + } + }, + + enableCreateLabel: function( $shipment ) { + var self = germanized.admin.shipments, + $button = $shipment.find( '.create-shipment-label' ); + + if ( $button.length > 0 ) { + $button.removeClass( 'disabled button-disabled' ); + $button.prop( 'title', self.params.i18n_create_label_enabled ); + } + }, + + setNeedsShipments: function( needsShipments ) { + var self = germanized.admin.shipments; + + if ( typeof needsShipments !== "boolean" ) { + needsShipments = true; + } + + self.needsShipments = needsShipments === true; + + if ( self.needsShipments ) { + self.$wrapper.addClass( 'needs-shipments' ); + self.$wrapper.find( '#order-shipment-add' ).show(); + } else { + self.$wrapper.removeClass( 'needs-shipments' ); + self.$wrapper.find( '#order-shipment-add' ).hide(); + } + + self.hideOrShowFooter(); + }, + + hideOrShowReturnTitle: function() { + var self = germanized.admin.shipments; + + if ( self.$wrapper.find( '.order-shipment.shipment-return' ).length === 0 ) { + self.$wrapper.find( '.panel-order-return-title' ).addClass( 'hide-default' ); + } else { + self.$wrapper.find( '.panel-order-return-title' ).removeClass( 'hide-default' ); + } + }, + + setNeedsReturns: function( needsReturns ) { + var self = germanized.admin.shipments; + + if ( typeof needsReturns !== "boolean" ) { + needsReturns = true; + } + + self.needsReturns = needsReturns === true; + + if ( self.needsReturns ) { + self.$wrapper.addClass( 'needs-returns' ); + self.$wrapper.find( '#order-return-shipment-add' ).show(); + } else { + self.$wrapper.removeClass( 'needs-returns' ); + self.$wrapper.find( '#order-return-shipment-add' ).hide(); + } + + self.hideOrShowFooter(); + }, + + hideOrShowFooter: function() { + var self = germanized.admin.shipments; + + if ( self.needsSaving || self.needsShipments || self.needsReturns ) { + self.$wrapper.find( '.panel-footer' ).slideDown( 300 ); + } else { + self.$wrapper.find( '.panel-footer' ).slideUp( 300 ); + } + }, + + onToggleShipment: function() { + var self = germanized.admin.shipments, + $shipment = $( this ).parents( '.order-shipment:first' ), + isActive = $shipment.hasClass( 'active' ); + + self.closeShipments(); + + if ( ! isActive ) { + $shipment.find( '> .shipment-content-wrapper' ).slideDown( 300, function() { + $shipment.addClass( 'active' ); + }); + } + }, + + closeShipments: function() { + var self = germanized.admin.shipments; + + self.$wrapper.find( '.order-shipment.active .shipment-content-wrapper' ).slideUp( 300, function() { + self.$wrapper.find( '.order-shipment.active' ).removeClass( 'active' ); + }); + }, + + initShipments: function() { + var self = germanized.admin.shipments; + + // Refresh wrapper + self.$wrapper = $( '#panel-order-shipments' ); + + self.$wrapper.find( '.order-shipment' ).each( function() { + var id = $( this ).data( 'shipment' ); + + self.initShipment( id ); + }); + + self.hideOrShowReturnTitle(); + }, + + getShipments: function() { + var self = germanized.admin.shipments; + + return self.shipments; + }, + + getShipment: function( shipment_id ) { + var self = germanized.admin.shipments, + shipments = self.getShipments(); + + if ( shipments.hasOwnProperty( shipment_id ) ) { + return shipments[ shipment_id ]; + } + + return false; + }, + + refresh: function( shipment_id ) { + + }, + + refreshItems: function( shipment_id ) { + + }, + + addItem: function() { + + }, + + initTiptip: function() { + var self = germanized.admin.shipments; + + // Tooltips + $( document.body ).trigger( 'init_tooltips' ); + + self.$wrapper.find( '.woocommerce-help-tip' ).tipTip({ + 'attribute': 'data-tip', + 'fadeIn': 50, + 'fadeOut': 50, + 'delay': 200 + }); + + self.$wrapper.find( '.create-shipment-label' ).tipTip( { + 'fadeIn': 50, + 'fadeOut': 50, + 'delay': 200 + } ); + }, + + backbone: { + + onAddReturnSuccess: function( data ) { + $( '#wc-gzd-return-shipment-items' ).html( data.html ); + $( '.wc-backbone-modal-content article' ).unblock(); + + $( document.body ).on( 'change', 'input.wc-gzd-shipment-add-return-item-quantity', function() { + var $select = $( this ), + quantity = $select.val(); + + if ( $select.attr( 'max' ) ) { + var maxQuantity = $select.attr( 'max' ); + + if ( quantity > maxQuantity ) { + $select.val( maxQuantity ); + } + } + }); + }, + + init: function ( e, target ) { + var self = germanized.admin.shipments; + + if( ( 'wc-gzd-modal-add-shipment-return' ) === target ) { + $( '.wc-backbone-modal-content article' ).block({ + message: null, + overlayCSS: { + background: '#fff', + opacity: 0.6 + } + }); + + self.doAjax( { + 'action' : 'woocommerce_gzd_get_available_return_shipment_items' + }, self.backbone.onAddReturnSuccess ); + + return false; + } + }, + + response: function ( e, target, data ) { + var self = germanized.admin.shipments; + + if( ( 'wc-gzd-modal-add-shipment-return' ) === target ) { + self.addReturn( data ); + } + } + } + }; + + $( document ).ready( function() { + germanized.admin.shipments.init(); + }); + +})( jQuery, window.germanized.admin ); diff --git a/packages/woocommerce-germanized-shipments/assets/js/admin-shipments.min.js b/packages/woocommerce-germanized-shipments/assets/js/admin-shipments.min.js new file mode 100644 index 000000000..abe1bfb1b --- /dev/null +++ b/packages/woocommerce-germanized-shipments/assets/js/admin-shipments.min.js @@ -0,0 +1 @@ +window.germanized=window.germanized||{},window.germanized.admin=window.germanized.admin||{},function(d){window.germanized.admin.shipments={params:{},shipments:{},$wrapper:!1,needsSaving:!1,needsShipments:!0,needsReturns:!1,init:function(){var e=germanized.admin.shipments;e.params=wc_gzd_admin_shipments_params,e.$wrapper=d("#panel-order-shipments"),e.needsShipments=e.$wrapper.find("#order-shipment-add").is(":visible"),e.needsReturns=e.$wrapper.find("#order-return-shipment-add").is(":visible"),e.initShipments(),d(document).ajaxComplete(e.onAjaxComplete),d(document).on("click","#order-shipments-list .shipment-header",e.onToggleShipment).on("change","#order-shipments-list :input:visible",e.setNeedsSaving).on("click","#panel-order-shipments #order-shipment-add",e.onAddShipment).on("click","#panel-order-shipments #order-return-shipment-add",e.onAddReturn).on("click","#panel-order-shipments .remove-shipment",e.onRemoveShipment).on("click","#panel-order-shipments button#order-shipments-save",e.onSave).on("click","#panel-order-shipments .notice-dismiss",e.onRemoveNotice),d(document.body).on("wc_backbone_modal_loaded",e.backbone.init).on("wc_backbone_modal_response",e.backbone.response)},onAjaxComplete:function(e,n,i){var t=germanized.admin.shipments;if(null!=n&&i.hasOwnProperty("data")){var n=i.data,i=!1;try{i=JSON.parse('{"'+n.replace(/&/g,'","').replace(/=/g,'":"')+'"}',function(e,n){return""===e?n:decodeURIComponent(n)})}catch(e){i=!1}i&&i.hasOwnProperty("action")&&("woocommerce_save_order_items"!==(n=i.action)&&"woocommerce_remove_order_item"!==n&&"woocommerce_add_order_item"!==n&&"woocommerce_delete_refund"!==n||t.syncItemQuantities())}},syncItemQuantities:function(){var e=germanized.admin.shipments,n=(e.block(),{action:"woocommerce_gzd_validate_shipment_item_quantities",active:e.getActiveShipmentId()});e.doAjax(n,e.onSyncSuccess)},onSyncSuccess:function(e){var n=germanized.admin.shipments;n.unblock(),n.initShipments(),n.initTiptip()},onSave:function(e){var n=germanized.admin.shipments;return e.preventDefault(),n.save(),!1},save:function(){var e=germanized.admin.shipments,n=(e.block(),{action:"woocommerce_gzd_save_shipments",active:e.getActiveShipmentId()});e.doAjax(n,e.onSaveSuccess)},initShipment:function(e){var n=germanized.admin.shipments;n.shipments.hasOwnProperty(e)?n.shipments[e].refreshDom():n.shipments[e]=new d.GermanizedShipment(e)},onSaveSuccess:function(e){var n=germanized.admin.shipments;n.initShipments(),n.setNeedsSaving(!1),n.unblock(),n.initTiptip()},getActiveShipmentId:function(){var e=germanized.admin.shipments.$wrapper.find(".order-shipment.active");return 0

'+e+'

')},getParams:function(){return germanized.admin.shipments.params},onRemoveShipment:function(){var e=germanized.admin.shipments,n=d(this).parents(".order-shipment").data("shipment");return window.confirm(e.getParams().i18n_remove_shipment_notice)&&e.removeShipment(n),!1},removeShipment:function(e){var n=germanized.admin.shipments,e={action:"woocommerce_gzd_remove_shipment",shipment_id:e};n.block(),n.doAjax(e,n.onRemoveShipmentSuccess,n.onRemoveShipmentError)},onRemoveShipmentSuccess:function(e){var t=germanized.admin.shipments,e=Array.isArray(e.shipment_id)?e.shipment_id:[e.shipment_id];d.each(e,function(e,n){var i=t.$wrapper.find("#shipment-"+n);0 .shipment-content-wrapper").slideDown(300,function(){n.addClass("active")})},closeShipments:function(){var e=germanized.admin.shipments;e.$wrapper.find(".order-shipment.active .shipment-content-wrapper").slideUp(300,function(){e.$wrapper.find(".order-shipment.active").removeClass("active")})},initShipments:function(){var n=germanized.admin.shipments;n.$wrapper=d("#panel-order-shipments"),n.$wrapper.find(".order-shipment").each(function(){var e=d(this).data("shipment");n.initShipment(e)}),n.hideOrShowReturnTitle()},getShipments:function(){return germanized.admin.shipments.shipments},getShipment:function(e){var n=germanized.admin.shipments.getShipments();return!!n.hasOwnProperty(e)&&n[e]},refresh:function(e){},refreshItems:function(e){},addItem:function(){},initTiptip:function(){var e=germanized.admin.shipments;d(document.body).trigger("init_tooltips"),e.$wrapper.find(".woocommerce-help-tip").tipTip({attribute:"data-tip",fadeIn:50,fadeOut:50,delay:200}),e.$wrapper.find(".create-shipment-label").tipTip({fadeIn:50,fadeOut:50,delay:200})},backbone:{onAddReturnSuccess:function(e){d("#wc-gzd-return-shipment-items").html(e.html),d(".wc-backbone-modal-content article").unblock(),d(document.body).on("change","input.wc-gzd-shipment-add-return-item-quantity",function(){var e,n=d(this),i=n.val();n.attr("max")&&(e=n.attr("max")) 0 ) { + $( 'select[id$=shipping_provider]' ).trigger( 'change' ); + } + }, + + onShippingMethodOpen: function( e, t ) { + if ( 'wc-modal-shipping-method-settings' === t ) { + if ( $( 'select[id$=shipping_provider]' ).length > 0 ) { + $( 'select[id$=shipping_provider]' ).trigger( 'change' ); + } + } + }, + + showOrHideAll: function() { + var self = germanized.admin.shipping_provider_method, + $select = $( this ), + $providers = $select.find( 'option' ), + $form = $select.parents( 'form' ); + + self.currentProvider = $select.val(); + + $providers.each( function() { + var $provider = $( this ), + provider_setting_prefix = $provider.val(); + + if ( provider_setting_prefix.length > 0 ) { + $form.find( 'table.form-table' ).each( function() { + if ( $( this ).find( ':input[id*=_' + provider_setting_prefix + '_]' ).length > 0 ) { + self.hideTable( $( this ) ); + } + }); + } + }); + + if ( self.currentProvider.length > 0 ) { + $form.find( 'table.form-table' ).each( function() { + if ( $( this ).find( ':input[id*=_' + self.currentProvider + '_]' ).length > 0 ) { + self.showTable( $( this ) ); + } + }); + } + }, + + hideTable: function( $table ) { + + if ( $table.find( 'select[id$=shipping_provider]' ).length > 0 ) { + return false; + } + + $table.prevUntil( 'table.form-table' ).hide(); + $table.hide(); + }, + + showTable: function( $table ) { + $table.prevUntil( 'table.form-table' ).show(); + $table.show(); + } + }; + + $( document ).ready( function() { + germanized.admin.shipping_provider_method.init(); + }); + +})( jQuery, window.germanized.admin ); diff --git a/packages/woocommerce-germanized-shipments/assets/js/admin-shipping-provider-method.min.js b/packages/woocommerce-germanized-shipments/assets/js/admin-shipping-provider-method.min.js new file mode 100644 index 000000000..1ed5adb2c --- /dev/null +++ b/packages/woocommerce-germanized-shipments/assets/js/admin-shipping-provider-method.min.js @@ -0,0 +1 @@ +window.germanized=window.germanized||{},window.germanized.admin=window.germanized.admin||{},function(r){window.germanized.admin.shipping_provider_method={params:{},currentProvider:"",init:function(){var i=germanized.admin.shipping_provider_method;i.params=wc_gzd_admin_shipping_provider_method_params,r(document).on("change","select[id$=shipping_provider]",i.showOrHideAll),r(document.body).on("wc_backbone_modal_loaded",i.onShippingMethodOpen),0 0 ) { + return $element.parents( 'tr' ).data( 'shipping-provider' ); + } + + return false; + }, + + onRemoveProvider: function() { + var self = germanized.admin.shipping_providers, + provider = self.getProviderName( $( this ) ); + + if ( provider ) { + var answer = window.confirm( self.getParams().i18n_remove_shipping_provider_notice ); + + if ( answer ) { + self.removeProvider( provider ); + } + } + + return false; + }, + + removeProvider: function( id ) { + var self = germanized.admin.shipping_providers, + params = { + 'action' : 'woocommerce_gzd_remove_shipping_provider', + 'provider': id, + 'security': self.getParams().remove_shipping_provider_nonce + }; + + self.block(); + self.doAjax( params, self.onRemoveProviderSuccess ); + }, + + onRemoveProviderSuccess: function( data ) { + var self = germanized.admin.shipping_providers, + $provider = self.$wrapper.find( 'tr[data-shipping-provider="' + data['provider'] + '"]' ); + + if ( $provider.length > 0 ) { + $provider.remove(); + } + }, + + block: function() { + var self = germanized.admin.shipping_providers; + + self.$wrapper.block({ + message: null, + overlayCSS: { + background: '#fff', + opacity: 0.6 + } + }); + }, + + unblock: function() { + var self = germanized.admin.shipping_providers; + + self.$wrapper.unblock(); + }, + + doAjax: function( params, cSuccess, cError ) { + var self = germanized.admin.shipping_providers, + url = self.params.ajax_url, + $wrapper = self.$wrapper; + + cSuccess = cSuccess || self.onAjaxSuccess; + cError = cError || self.onAjaxError; + + if ( ! params.hasOwnProperty( 'security' ) ) { + params['security'] = self.params.edit_shipping_providers_nonce; + } + + $.ajax({ + type: "POST", + url: url, + data: params, + success: function( data ) { + if ( data.success ) { + cSuccess.apply( $wrapper, [ data ] ); + self.unblock(); + } else { + cError.apply( $wrapper, [ data ] ); + self.unblock(); + } + }, + error: function( data ) { + cError.apply( $wrapper, [ data ] ); + }, + dataType: 'json' + }); + }, + + onAjaxError: function( data ) { + + }, + + onAjaxSuccess: function( data ) { + + }, + + getParams: function() { + var self = germanized.admin.shipping_providers; + + return self.params; + } + }; + + $( document ).ready( function() { + germanized.admin.shipping_providers.init(); + }); + +})( jQuery, window.germanized.admin ); diff --git a/packages/woocommerce-germanized-shipments/assets/js/admin-shipping-providers.min.js b/packages/woocommerce-germanized-shipments/assets/js/admin-shipping-providers.min.js new file mode 100644 index 000000000..ea5aaf1dc --- /dev/null +++ b/packages/woocommerce-germanized-shipments/assets/js/admin-shipping-providers.min.js @@ -0,0 +1 @@ +window.germanized=window.germanized||{},window.germanized.admin=window.germanized.admin||{},function(d){window.germanized.admin.shipping_providers={params:{},$wrapper:"",init:function(){var e=germanized.admin.shipping_providers;e.params=wc_gzd_admin_shipping_providers_params,e.$wrapper=d(".wc-gzd-shipping-providers"),d(document).on("click",".wc-gzd-shipping-provider-delete",e.onRemoveProvider).on("change",".wc-gzd-shipping-providers input.wc-gzd-shipping-provider-activated-checkbox",this.onChangeProviderStatus)},onChangeProviderStatus:function(){var e=germanized.admin.shipping_providers,i=d(this),r=e.getProviderName(i),n=i.parents("td").find(".woocommerce-gzd-input-toggle"),i={action:"woocommerce_gzd_edit_shipping_provider_status",enable:i.is(":checked")?"yes":"no",provider:r};window.onbeforeunload="",n.addClass("woocommerce-input-toggle--loading"),e.doAjax(i,e.onChangeProviderStatusSucess)},onChangeProviderStatusSucess:function(e){var i=germanized.admin.shipping_providers.$wrapper.find('tr[data-shipping-provider="'+e.provider+'"]').find(".woocommerce-gzd-input-toggle");i.removeClass("woocommerce-input-toggle--loading"),i.removeClass("woocommerce-input-toggle--enabled, woocommerce-input-toggle--disabled"),"yes"===e.activated?i.addClass("woocommerce-input-toggle--enabled"):i.addClass("woocommerce-input-toggle--disabled")},getProviderName:function(e){germanized.admin.shipping_providers;return e.data("shipping-provider")?e.data("shipping-provider"):0 + +get_available_items_for_return() as $item_id => $item_data ) : + ?> + + + + + diff --git a/packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipment-content.php b/packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipment-content.php new file mode 100644 index 000000000..5c7a9b3e5 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipment-content.php @@ -0,0 +1,261 @@ + + +
+
+ + +
+
+
+

+ + +

+
+
+

+ + + + has_packaging() ? 'disabled="disabled"' : '' ); ?> size="6" class="wc_input_decimal wc-gzd-shipment-dimension has_packaging() ? 'disabled' : '' ); ?>" value="get_length( 'edit' ) ) ); ?>" name="shipment_length[get_id() ); ?>]" id="shipment-length-get_id() ); ?>" placeholder="get_content_length() ) ); ?>" /> + has_packaging() ? 'disabled="disabled"' : '' ); ?> size="6" class="wc_input_decimal wc-gzd-shipment-dimension has_packaging() ? 'disabled' : '' ); ?>" value="get_width( 'edit' ) ) ); ?>" name="shipment_width[get_id() ); ?>]" id="shipment-width-get_id() ); ?>" placeholder="get_content_width() ) ); ?>" /> + has_packaging() ? 'disabled="disabled"' : '' ); ?> size="6" class="wc_input_decimal wc-gzd-shipment-dimension has_packaging() ? 'disabled' : '' ); ?>" value="get_height( 'edit' ) ) ); ?>" name="shipment_height[get_id() ); ?>]" id="shipment-height-get_id() ); ?>" placeholder="get_content_height() ) ); ?>" /> + +

+
+
+ +

+ + + +

+
+ +
+

+ + +

+ + get_available_shipping_methods() ) > 1 ) : ?> +

+ + +

+ + +

+ + +

+ +

+ + +

+ + +
+ +
+
+
+
+ supports_label() && ( ( $label = $shipment->get_label() ) || $shipment->needs_label() ) ) : + include 'label/html-shipment-label.php'; + endif; + ?> +
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+ $column ) : ?> +
+ +
+ +
+
+ +
+ get_items() as $item ) : ?> + + +
+
+ +
+
+ +
+ +
+ +
+ + +
+
+ +
+ + + + +
+
diff --git a/packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipment-item-count.php b/packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipment-item-count.php new file mode 100644 index 000000000..4028a912b --- /dev/null +++ b/packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipment-item-count.php @@ -0,0 +1,19 @@ + + + + get_shippable_item_count() ) > 0 ) : + $item_count = $shipment->get_item_count(); + ?> + + + diff --git a/packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipment-item.php b/packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipment-item.php new file mode 100644 index 000000000..8fe650fd2 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipment-item.php @@ -0,0 +1,69 @@ + + +
+
+ $column ) : ?> + +
+ + + + get_name() ); ?> get_sku() ? '(' . esc_html( $item->get_sku() ) . ')' : '' ); ?> + + + + + + + + + + + + + + + + get_id(), $item, $shipment, $column_name ); + ?> +
+ + +
+ + +
diff --git a/packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipment-list.php b/packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipment-list.php new file mode 100644 index 000000000..44a6178c0 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipment-list.php @@ -0,0 +1,36 @@ +get_return_shipments(); +?> + +
+ get_simple_shipments() as $shipment ) : + $is_active = ( $active_shipment && $shipment->get_id() === $active_shipment ) ? true : false; + + include 'html-order-shipment.php'; + ?> + + +
+

+ get_return_status() ) ); ?> +
+ + + get_id() === $active_shipment ) ? true : false; + include 'html-order-shipment.php'; + ?> + + +
diff --git a/packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipment-packaging-select.php b/packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipment-packaging-select.php new file mode 100644 index 000000000..36b6cc82a --- /dev/null +++ b/packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipment-packaging-select.php @@ -0,0 +1,35 @@ +get_available_packaging(); +$current_packaging_id = $shipment->get_packaging_id(); +$default_packaging_id = \Vendidero\Germanized\Shipments\Package::get_setting( 'default_packaging' ); +$default_packaging = ! empty( $default_packaging_id ) ? wc_gzd_get_packaging( $default_packaging_id ) : false; +$default_exists_in_list = false; +?> + diff --git a/packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipment.php b/packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipment.php new file mode 100644 index 000000000..56da49e48 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipment.php @@ -0,0 +1,31 @@ + + +
+
+
+

get_type() ) ), esc_html( $shipment->get_id() ) ); ?>

+ get_status() ) ); ?> +
+ +
+ + +
+
+ +
+ +
+
diff --git a/packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipments.php b/packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipments.php new file mode 100644 index 000000000..9f04ed95b --- /dev/null +++ b/packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipments.php @@ -0,0 +1,94 @@ + + +
+
+ +
+

+ get_shipping_status() ) ); ?> +
+ +
+ + + + +
+
diff --git a/packages/woocommerce-germanized-shipments/includes/admin/views/html-settings-provider-list.php b/packages/woocommerce-germanized-shipments/includes/admin/views/html-settings-provider-list.php new file mode 100644 index 000000000..0bd5f387f --- /dev/null +++ b/packages/woocommerce-germanized-shipments/includes/admin/views/html-settings-provider-list.php @@ -0,0 +1,68 @@ + + + + + + + + + + + + + $provider ) : ?> + + + + + + + + +
+ get_title() ); ?> +
+ + is_manual_integration() ) : ?> + | + + +
+
+

get_description() ); ?>

+
+
+ + is_activated() ? 'yes' : 'no', 'yes' ); ?> + /> +
+
+ get_help_link() ) : ?> + + + + +
diff --git a/packages/woocommerce-germanized-shipments/includes/admin/views/label/html-shipment-label-backbone-error.php b/packages/woocommerce-germanized-shipments/includes/admin/views/label/html-shipment-label-backbone-error.php new file mode 100644 index 000000000..600c9684e --- /dev/null +++ b/packages/woocommerce-germanized-shipments/includes/admin/views/label/html-shipment-label-backbone-error.php @@ -0,0 +1,22 @@ + +
+ +
+ get_error_messages() as $message ) : ?> +
+ +
+ +
+
diff --git a/packages/woocommerce-germanized-shipments/includes/admin/views/label/html-shipment-label-backbone-form.php b/packages/woocommerce-germanized-shipments/includes/admin/views/label/html-shipment-label-backbone-form.php new file mode 100644 index 000000000..42a9b6f0c --- /dev/null +++ b/packages/woocommerce-germanized-shipments/includes/admin/views/label/html-shipment-label-backbone-form.php @@ -0,0 +1,17 @@ + +
+ + + +
diff --git a/packages/woocommerce-germanized-shipments/includes/admin/views/label/html-shipment-label-backbone.php b/packages/woocommerce-germanized-shipments/includes/admin/views/label/html-shipment-label-backbone.php new file mode 100644 index 000000000..b1f35edf3 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/includes/admin/views/label/html-shipment-label-backbone.php @@ -0,0 +1,34 @@ + + + diff --git a/packages/woocommerce-germanized-shipments/includes/admin/views/label/html-shipment-label.php b/packages/woocommerce-germanized-shipments/includes/admin/views/label/html-shipment-label.php new file mode 100644 index 000000000..8133d77b9 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/includes/admin/views/label/html-shipment-label.php @@ -0,0 +1,49 @@ + + +
+

get_shipping_provider() ) ) ); ?> has_label() && $shipment->get_tracking_id() ) ? wp_kses_post( Admin::get_shipment_tracking_html( $shipment ) ) : '' ); ?>

+ +
+
+ +
+ get_file() ) : ?> + + + + + +
+ +
+ + + +
+ +
+
+
diff --git a/packages/woocommerce-germanized-shipments/includes/emails/class-wc-gzd-email-customer-guest-return-shipment-request.php b/packages/woocommerce-germanized-shipments/includes/emails/class-wc-gzd-email-customer-guest-return-shipment-request.php new file mode 100644 index 000000000..55e2ea4a4 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/includes/emails/class-wc-gzd-email-customer-guest-return-shipment-request.php @@ -0,0 +1,214 @@ +customer_email = true; + $this->id = 'customer_guest_return_shipment_request'; + $this->title = _x( 'Order guest return request', 'shipments', 'woocommerce-germanized' ); + $this->description = _x( 'Order guest return request are sent to the customer after submitting a new return request as a guest.', 'shipments', 'woocommerce-germanized' ); + + $this->template_html = 'emails/customer-guest-return-shipment-request.php'; + $this->template_plain = 'emails/plain/customer-guest-return-shipment-request.php'; + $this->template_base = Package::get_path() . '/templates/'; + $this->helper = function_exists( 'wc_gzd_get_email_helper' ) ? wc_gzd_get_email_helper( $this ) : false; + + $this->placeholders = array( + '{site_title}' => $this->get_blogname(), + '{order_number}' => '', + '{order_date}' => '', + ); + + // Call parent constructor. + parent::__construct(); + } + + /** + * Get email subject. + * + * @since 3.1.0 + * @return string + */ + public function get_default_subject() { + return _x( 'Your return request to your order {order_number}', 'shipments', 'woocommerce-germanized' ); + } + + /** + * Get email heading. + * + * @since 3.1.0 + * @return string + */ + public function get_default_heading() { + return _x( 'Return request to your order: {order_number}', 'shipments', 'woocommerce-germanized' ); + } + + /** + * Switch Woo and Germanized locale + */ + public function setup_locale() { + + if ( $this->is_customer_email() && function_exists( 'wc_gzd_switch_to_site_locale' ) && apply_filters( 'woocommerce_email_setup_locale', true ) ) { + wc_gzd_switch_to_site_locale(); + } + + parent::setup_locale(); + } + + /** + * Restore Woo and Germanized locale + */ + public function restore_locale() { + + if ( $this->is_customer_email() && function_exists( 'wc_gzd_restore_locale' ) && apply_filters( 'woocommerce_email_restore_locale', true ) ) { + wc_gzd_restore_locale(); + } + + parent::restore_locale(); + } + + /** + * Trigger. + * + * @param int $order_id order ID. + */ + public function trigger( $order_id ) { + if ( $this->helper ) { + $this->helper->setup_locale(); + } else { + $this->setup_locale(); + } + + if ( $this->object = wc_get_order( $order_id ) ) { + + $this->placeholders['{order_number}'] = $this->object->get_order_number(); + + if ( ( $order_shipment = wc_gzd_get_shipment_order( $this->object ) ) && ( $this->request_url = wc_gzd_get_order_customer_add_return_url( $this->object ) ) ) { + $this->recipient = $this->object->get_billing_email(); + $this->placeholders['{order_date}'] = wc_format_datetime( $this->object->get_date_created() ); + $this->placeholders['{order_number}'] = $this->object->get_order_number(); + } + } + + if ( $this->helper ) { + $this->helper->setup_email_locale(); + } + + if ( $this->is_enabled() && $this->get_recipient() ) { + $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() ); + } + + if ( $this->helper ) { + $this->helper->restore_email_locale(); + } + + if ( $this->helper ) { + $this->helper->restore_locale(); + } else { + $this->restore_locale(); + } + } + + /** + * Return content from the additional_content field. + * + * Displayed above the footer. + * + * @since 2.0.4 + * @return string + */ + public function get_additional_content() { + if ( is_callable( 'parent::get_additional_content' ) ) { + return parent::get_additional_content(); + } + + return ''; + } + + /** + * Get content html. + * + * @return string + */ + public function get_content_html() { + return wc_get_template_html( + $this->template_html, + array( + 'order' => $this->object, + 'add_return_request_url' => $this->request_url, + 'email_heading' => $this->get_heading(), + 'additional_content' => $this->get_additional_content(), + 'sent_to_admin' => false, + 'plain_text' => false, + 'email' => $this, + ) + ); + } + + /** + * Get content plain. + * + * @return string + */ + public function get_content_plain() { + return wc_get_template_html( + $this->template_plain, + array( + 'order' => $this->object, + 'add_return_request_url' => $this->request_url, + 'email_heading' => $this->get_heading(), + 'additional_content' => $this->get_additional_content(), + 'sent_to_admin' => false, + 'plain_text' => true, + 'email' => $this, + ) + ); + } + + /** + * Default content to show below main email content. + * + * @since 1.0.1 + * @return string + */ + public function get_default_additional_content() { + return ''; + } + } + +endif; + +return new WC_GZD_Email_Customer_Guest_Return_Shipment_Request(); diff --git a/packages/woocommerce-germanized-shipments/includes/emails/class-wc-gzd-email-customer-return-shipment-delivered.php b/packages/woocommerce-germanized-shipments/includes/emails/class-wc-gzd-email-customer-return-shipment-delivered.php new file mode 100644 index 000000000..9b319386d --- /dev/null +++ b/packages/woocommerce-germanized-shipments/includes/emails/class-wc-gzd-email-customer-return-shipment-delivered.php @@ -0,0 +1,234 @@ +customer_email = true; + $this->id = 'customer_return_shipment_delivered'; + $this->title = _x( 'Order return delivered', 'shipments', 'woocommerce-germanized' ); + $this->description = _x( 'Order return notifications are sent to the customer after a return shipment has been returned (delivered) successfully.', 'shipments', 'woocommerce-germanized' ); + + $this->template_html = 'emails/customer-return-shipment-delivered.php'; + $this->template_plain = 'emails/plain/customer-return-shipment-delivered.php'; + $this->template_base = Package::get_path() . '/templates/'; + $this->helper = function_exists( 'wc_gzd_get_email_helper' ) ? wc_gzd_get_email_helper( $this ) : false; + + $this->placeholders = array( + '{site_title}' => $this->get_blogname(), + '{shipment_number}' => '', + '{order_number}' => '', + '{order_date}' => '', + '{date_sent}' => '', + ); + + // Triggers for this email. + add_action( 'woocommerce_gzd_return_shipment_status_processing_to_delivered_notification', array( $this, 'trigger' ), 10 ); + add_action( 'woocommerce_gzd_return_shipment_status_shipped_to_delivered_notification', array( $this, 'trigger' ), 10 ); + + // Call parent constructor. + parent::__construct(); + } + + /** + * Get email subject. + * + * @since 3.1.0 + * @return string + */ + public function get_default_subject() { + return _x( 'Return to your order {order_number} has been received', 'shipments', 'woocommerce-germanized' ); + } + + /** + * Get email heading. + * + * @since 3.1.0 + * @return string + */ + public function get_default_heading() { + return _x( 'Received return to your order: {order_number}', 'shipments', 'woocommerce-germanized' ); + } + + /** + * Switch Woo and Germanized locale + */ + public function setup_locale() { + + if ( $this->is_customer_email() && function_exists( 'wc_gzd_switch_to_site_locale' ) && apply_filters( 'woocommerce_email_setup_locale', true ) ) { + wc_gzd_switch_to_site_locale(); + } + + parent::setup_locale(); + } + + /** + * Restore Woo and Germanized locale + */ + public function restore_locale() { + + if ( $this->is_customer_email() && function_exists( 'wc_gzd_restore_locale' ) && apply_filters( 'woocommerce_email_restore_locale', true ) ) { + wc_gzd_restore_locale(); + } + + parent::restore_locale(); + } + + /** + * Trigger. + * + * @param int $shipment_id Shipment ID. + * @param bool $is_confirmation + */ + public function trigger( $shipment_id ) { + if ( $this->helper ) { + $this->helper->setup_locale(); + } else { + $this->setup_locale(); + } + + if ( $this->shipment = wc_gzd_get_shipment( $shipment_id ) ) { + + if ( 'return' !== $this->shipment->get_type() ) { + return; + } + + $this->placeholders['{shipment_number}'] = $this->shipment->get_shipment_number(); + + if ( $order_shipment = wc_gzd_get_shipment_order( $this->shipment->get_order() ) ) { + + $this->object = $this->shipment->get_order(); + $this->recipient = $order_shipment->get_order()->get_billing_email(); + $this->placeholders['{order_date}'] = wc_format_datetime( $order_shipment->get_order()->get_date_created() ); + $this->placeholders['{order_number}'] = $order_shipment->get_order()->get_order_number(); + + if ( $this->shipment->get_date_sent() ) { + $this->placeholders['{date_sent}'] = wc_format_datetime( $this->shipment->get_date_sent() ); + } + } + } + + if ( $this->helper ) { + $this->helper->setup_email_locale(); + } + + if ( $this->is_enabled() && $this->get_recipient() ) { + $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() ); + } + + if ( $this->helper ) { + $this->helper->restore_email_locale(); + } + + if ( $this->helper ) { + $this->helper->restore_locale(); + } else { + $this->restore_locale(); + } + } + + /** + * Return content from the additional_content field. + * + * Displayed above the footer. + * + * @since 2.0.4 + * @return string + */ + public function get_additional_content() { + if ( is_callable( 'parent::get_additional_content' ) ) { + return parent::get_additional_content(); + } + + return ''; + } + + /** + * Get content html. + * + * @return string + */ + public function get_content_html() { + return wc_get_template_html( + $this->template_html, + array( + 'shipment' => $this->shipment, + 'order' => $this->object, + 'email_heading' => $this->get_heading(), + 'additional_content' => $this->get_additional_content(), + 'sent_to_admin' => false, + 'plain_text' => false, + 'email' => $this, + ) + ); + } + + /** + * Get content plain. + * + * @return string + */ + public function get_content_plain() { + return wc_get_template_html( + $this->template_plain, + array( + 'shipment' => $this->shipment, + 'order' => $this->object, + 'email_heading' => $this->get_heading(), + 'additional_content' => $this->get_additional_content(), + 'sent_to_admin' => false, + 'plain_text' => true, + 'email' => $this, + ) + ); + } + + /** + * Default content to show below main email content. + * + * @since 1.0.1 + * @return string + */ + public function get_default_additional_content() { + return ''; + } + } + +endif; + +return new WC_GZD_Email_Customer_Return_Shipment_Delivered(); diff --git a/packages/woocommerce-germanized-shipments/includes/emails/class-wc-gzd-email-customer-return-shipment.php b/packages/woocommerce-germanized-shipments/includes/emails/class-wc-gzd-email-customer-return-shipment.php new file mode 100644 index 000000000..3687a3ec4 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/includes/emails/class-wc-gzd-email-customer-return-shipment.php @@ -0,0 +1,267 @@ +customer_email = true; + $this->id = 'customer_return_shipment'; + $this->title = _x( 'Order return', 'shipments', 'woocommerce-germanized' ); + $this->description = _x( 'Order return notifications are sent to the customer after a return shipment was marked as processing.', 'shipments', 'woocommerce-germanized' ); + + $this->template_html = 'emails/customer-return-shipment.php'; + $this->template_plain = 'emails/plain/customer-return-shipment.php'; + $this->template_base = Package::get_path() . '/templates/'; + $this->helper = function_exists( 'wc_gzd_get_email_helper' ) ? wc_gzd_get_email_helper( $this ) : false; + + $this->placeholders = array( + '{site_title}' => $this->get_blogname(), + '{shipment_number}' => '', + '{order_number}' => '', + '{order_date}' => '', + '{date_sent}' => '', + ); + + // Triggers for this email. + add_action( 'woocommerce_gzd_return_shipment_status_draft_to_processing_notification', array( $this, 'trigger' ), 10 ); + add_action( 'woocommerce_gzd_return_shipment_status_requested_to_processing_notification', array( $this, 'trigger' ), 10 ); + + // Call parent constructor. + parent::__construct(); + } + + /** + * Get email subject. + * + * @since 3.1.0 + * @return string + */ + public function get_default_subject() { + return _x( 'Return to your order {order_number}', 'shipments', 'woocommerce-germanized' ); + } + + /** + * Get email heading. + * + * @since 3.1.0 + * @return string + */ + public function get_default_heading() { + return _x( 'Return to your order: {order_number}', 'shipments', 'woocommerce-germanized' ); + } + + /** + * Switch Woo and Germanized locale + */ + public function setup_locale() { + + if ( $this->is_customer_email() && function_exists( 'wc_gzd_switch_to_site_locale' ) && apply_filters( 'woocommerce_email_setup_locale', true ) ) { + wc_gzd_switch_to_site_locale(); + } + + parent::setup_locale(); + } + + /** + * Restore Woo and Germanized locale + */ + public function restore_locale() { + + if ( $this->is_customer_email() && function_exists( 'wc_gzd_restore_locale' ) && apply_filters( 'woocommerce_email_restore_locale', true ) ) { + wc_gzd_restore_locale(); + } + + parent::restore_locale(); + } + + /** + * Trigger. + * + * @param int $shipment_id Shipment ID. + * @param bool $is_confirmation + */ + public function trigger( $shipment_id, $is_confirmation = false ) { + if ( $this->helper ) { + $this->helper->setup_locale(); + } else { + $this->setup_locale(); + } + + $this->is_confirmation = $is_confirmation; + + if ( $this->shipment = wc_gzd_get_shipment( $shipment_id ) ) { + + if ( 'return' !== $this->shipment->get_type() ) { + return; + } + + // Check if this is a customer request. + if ( $this->shipment->is_customer_requested() ) { + $this->is_confirmation = true; + } + + $this->placeholders['{shipment_number}'] = $this->shipment->get_shipment_number(); + + if ( $order_shipment = wc_gzd_get_shipment_order( $this->shipment->get_order() ) ) { + + $this->object = $this->shipment->get_order(); + $this->recipient = $order_shipment->get_order()->get_billing_email(); + $this->placeholders['{order_date}'] = wc_format_datetime( $order_shipment->get_order()->get_date_created() ); + $this->placeholders['{order_number}'] = $order_shipment->get_order()->get_order_number(); + + if ( $this->shipment->get_date_sent() ) { + $this->placeholders['{date_sent}'] = wc_format_datetime( $this->shipment->get_date_sent() ); + } + } + } + + $this->id = 'customer_return_shipment'; + + if ( $this->helper ) { + $this->helper->setup_email_locale(); + } + + if ( $this->is_enabled() && $this->get_recipient() ) { + $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() ); + } + + if ( $this->helper ) { + $this->helper->restore_email_locale(); + } + + if ( $this->helper ) { + $this->helper->restore_locale(); + } else { + $this->restore_locale(); + } + } + + /** + * Return content from the additional_content field. + * + * Displayed above the footer. + * + * @since 2.0.4 + * @return string + */ + public function get_additional_content() { + if ( is_callable( 'parent::get_additional_content' ) ) { + return parent::get_additional_content(); + } + + return ''; + } + + /** + * Get content html. + * + * @return string + */ + public function get_content_html() { + return wc_get_template_html( + $this->template_html, + array( + 'shipment' => $this->shipment, + 'order' => $this->object, + 'is_confirmation' => $this->is_confirmation, + 'email_heading' => $this->get_heading(), + 'additional_content' => $this->get_additional_content(), + 'sent_to_admin' => false, + 'plain_text' => false, + 'email' => $this, + ) + ); + } + + /** + * Get content plain. + * + * @return string + */ + public function get_content_plain() { + return wc_get_template_html( + $this->template_plain, + array( + 'shipment' => $this->shipment, + 'order' => $this->object, + 'is_confirmation' => $this->is_confirmation, + 'email_heading' => $this->get_heading(), + 'additional_content' => $this->get_additional_content(), + 'sent_to_admin' => false, + 'plain_text' => true, + 'email' => $this, + ) + ); + } + + public function get_attachments() { + $attachments = array(); + + if ( $this->shipment->has_label() ) { + $label = $this->shipment->get_label(); + + if ( $file = $label->get_file() ) { + $attachments[] = $file; + } + } + + return apply_filters( 'woocommerce_email_attachments', $attachments, $this->id, $this->object, $this ); + } + + /** + * Default content to show below main email content. + * + * @since 1.0.1 + * @return string + */ + public function get_default_additional_content() { + return ''; + } + } + +endif; + +return new WC_GZD_Email_Customer_Return_Shipment(); diff --git a/packages/woocommerce-germanized-shipments/includes/emails/class-wc-gzd-email-customer-shipment.php b/packages/woocommerce-germanized-shipments/includes/emails/class-wc-gzd-email-customer-shipment.php new file mode 100644 index 000000000..2fffd6cd0 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/includes/emails/class-wc-gzd-email-customer-shipment.php @@ -0,0 +1,415 @@ +customer_email = true; + $this->id = 'customer_shipment'; + $this->title = _x( 'Order shipped', 'shipments', 'woocommerce-germanized' ); + $this->description = _x( 'Shipment notifications are sent to the customer when a shipment gets shipped.', 'shipments', 'woocommerce-germanized' ); + + $this->template_html = 'emails/customer-shipment.php'; + $this->template_plain = 'emails/plain/customer-shipment.php'; + $this->template_base = Package::get_path() . '/templates/'; + $this->helper = function_exists( 'wc_gzd_get_email_helper' ) ? wc_gzd_get_email_helper( $this ) : false; + + $this->placeholders = array( + '{site_title}' => $this->get_blogname(), + '{shipment_number}' => '', + '{order_number}' => '', + '{order_date}' => '', + '{date_sent}' => '', + '{current_shipment_num}' => '', + '{total_shipments}' => '', + ); + + // Triggers for this email. + if ( 'yes' === Package::get_setting( 'notify_enable' ) ) { + add_action( 'woocommerce_gzd_shipment_status_draft_to_shipped_notification', array( $this, 'trigger' ), 10 ); + add_action( 'woocommerce_gzd_shipment_status_processing_to_shipped_notification', array( $this, 'trigger' ), 10 ); + } + + // Call parent constructor. + parent::__construct(); + } + + /** + * Get email subject. + * + * @param bool $partial Whether it is a partial refund or a full refund. + * @since 3.1.0 + * @return string + */ + public function get_default_subject( $partial = false ) { + if ( $partial ) { + return _x( 'Your {site_title} order #{order_number} has been partially shipped ({current_shipment_num}/{total_shipments})', 'shipments', 'woocommerce-germanized' ); + } else { + return _x( 'Your {site_title} order #{order_number} has been shipped ({current_shipment_num}/{total_shipments})', 'shipments', 'woocommerce-germanized' ); + } + } + + /** + * Get email heading. + * + * @param bool $partial Whether it is a partial refund or a full refund. + * @since 3.1.0 + * @return string + */ + public function get_default_heading( $partial = false ) { + if ( $partial ) { + return _x( 'Partial shipment to your order: {order_number}', 'shipments', 'woocommerce-germanized' ); + } else { + return _x( 'Shipment to your order: {order_number}', 'shipments', 'woocommerce-germanized' ); + } + } + + /** + * Get email subject. + * + * @return string + */ + public function get_subject() { + if ( $this->partial_shipment ) { + $subject = $this->get_option( 'subject_partial', $this->get_default_subject( true ) ); + } else { + $subject = $this->get_option( 'subject_full', $this->get_default_subject() ); + } + + /** + * Filter to adjust the email subject for a shipped Shipment. + * + * @param string $subject The subject. + * @param WC_GZD_Email_Customer_Shipment $email The email instance. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_email_subject_customer_shipment', $this->format_string( $subject ), $this->object, $this ); + } + + /** + * Get email heading. + * + * @return string + */ + public function get_heading() { + if ( $this->partial_shipment ) { + $heading = $this->get_option( 'heading_partial', $this->get_default_heading( true ) ); + } else { + $heading = $this->get_option( 'heading_full', $this->get_default_heading() ); + } + + /** + * Filter to adjust the email heading for a shipped Shipment. + * + * @param string $heading The heading. + * @param WC_GZD_Email_Customer_Shipment $email The email instance. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_email_heading_customer_shipment', $this->format_string( $heading ), $this->object, $this ); + } + + /** + * Switch Woo and Germanized locale + */ + public function setup_locale() { + + if ( $this->is_customer_email() && function_exists( 'wc_gzd_switch_to_site_locale' ) && apply_filters( 'woocommerce_email_setup_locale', true ) ) { + wc_gzd_switch_to_site_locale(); + } + + parent::setup_locale(); + } + + /** + * Restore Woo and Germanized locale + */ + public function restore_locale() { + + if ( $this->is_customer_email() && function_exists( 'wc_gzd_restore_locale' ) && apply_filters( 'woocommerce_email_restore_locale', true ) ) { + wc_gzd_restore_locale(); + } + + parent::restore_locale(); + } + + public function get_shipped_position_number( $shipment_id ) { + $shipped_count = 1; + + if ( ! $this->object || ( ! $order = wc_gzd_get_shipment_order( $this->object ) ) ) { + return $shipped_count; + } + + if ( is_a( $shipment_id, '\Vendidero\Germanized\Shipments\Shipment' ) ) { + $shipment_id = $shipment_id->get_id(); + } + + if ( ! is_numeric( $shipment_id ) ) { + return $shipped_count; + } + + foreach ( $order->get_simple_shipments() as $key => $shipment ) { + if ( $shipment->is_shipped() ) { + if ( (int) $shipment->get_id() !== (int) $shipment_id ) { + $shipped_count++; + } + } + } + + return $shipped_count; + } + + /** + * Trigger. + * + * @param int $shipment_id Shipment ID. + */ + public function trigger( $shipment_id ) { + if ( $this->helper ) { + $this->helper->setup_locale(); + } else { + $this->setup_locale(); + } + + $this->partial_shipment = false; + + if ( $this->shipment = wc_gzd_get_shipment( $shipment_id ) ) { + + $this->placeholders['{shipment_number}'] = $this->shipment->get_shipment_number(); + + if ( $order_shipment = wc_gzd_get_shipment_order( $this->shipment->get_order() ) ) { + $this->object = $this->shipment->get_order(); + $this->total_shipments = count( $order_shipment->get_simple_shipments() ); + $this->cur_position = $this->get_shipped_position_number( $shipment_id ); + + if ( $order_shipment->needs_shipping() || $this->total_shipments > 1 ) { + if ( $order_shipment->needs_shipping() || ( $this->cur_position < $this->total_shipments ) ) { + $this->partial_shipment = true; + } + } + + $this->recipient = $order_shipment->get_order()->get_billing_email(); + $this->placeholders['{order_date}'] = wc_format_datetime( $order_shipment->get_order()->get_date_created() ); + $this->placeholders['{order_number}'] = $order_shipment->get_order()->get_order_number(); + $this->placeholders['{total_shipments}'] = $this->total_shipments; + $this->placeholders['{current_shipment_num}'] = $this->cur_position; + + if ( $this->shipment->get_date_sent() ) { + $this->placeholders['{date_sent}'] = wc_format_datetime( $this->shipment->get_date_sent() ); + } + } + } + + $this->id = $this->partial_shipment ? 'customer_partial_shipment' : 'customer_shipment'; + + if ( $this->helper ) { + $this->helper->setup_email_locale(); + } + + if ( $this->is_enabled() && $this->get_recipient() ) { + $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() ); + } + + if ( $this->helper ) { + $this->helper->restore_email_locale(); + } + + if ( $this->helper ) { + $this->helper->restore_locale(); + } else { + $this->restore_locale(); + } + } + + /** + * Return content from the additional_content field. + * + * Displayed above the footer. + * + * @since 2.0.4 + * @return string + */ + public function get_additional_content() { + if ( is_callable( 'parent::get_additional_content' ) ) { + return parent::get_additional_content(); + } + + return ''; + } + + /** + * Get content html. + * + * @return string + */ + public function get_content_html() { + return wc_get_template_html( + $this->template_html, + array( + 'shipment' => $this->shipment, + 'order' => $this->object, + 'partial_shipment' => $this->partial_shipment, + 'cur_position' => $this->cur_position, + 'total_shipments' => $this->total_shipments, + 'email_heading' => $this->get_heading(), + 'additional_content' => $this->get_additional_content(), + 'sent_to_admin' => false, + 'plain_text' => false, + 'email' => $this, + ) + ); + } + + /** + * Get content plain. + * + * @return string + */ + public function get_content_plain() { + return wc_get_template_html( + $this->template_plain, + array( + 'shipment' => $this->shipment, + 'order' => $this->object, + 'partial_shipment' => $this->partial_shipment, + 'cur_position' => $this->cur_position, + 'total_shipments' => $this->total_shipments, + 'email_heading' => $this->get_heading(), + 'additional_content' => $this->get_additional_content(), + 'sent_to_admin' => false, + 'plain_text' => true, + 'email' => $this, + ) + ); + } + + /** + * Default content to show below main email content. + * + * @since 1.0.1 + * @return string + */ + public function get_default_additional_content() { + return ''; + } + + /** + * Initialise settings form fields. + */ + public function init_form_fields() { + /* translators: %s: list of placeholders */ + $placeholder_text = sprintf( _x( 'Available placeholders: %s', 'shipments', 'woocommerce-germanized' ), '' . esc_html( implode( ', ', array_keys( $this->placeholders ) ) ) . '' ); + + $this->form_fields = array( + 'enabled' => array( + 'title' => _x( 'Enable/Disable', 'shipments', 'woocommerce-germanized' ), + 'type' => 'checkbox', + 'label' => _x( 'Enable this email notification', 'shipments', 'woocommerce-germanized' ), + 'default' => 'yes', + ), + 'subject_full' => array( + 'title' => _x( 'Full shipment subject', 'shipments', 'woocommerce-germanized' ), + 'type' => 'text', + 'desc_tip' => true, + 'description' => $placeholder_text, + 'placeholder' => $this->get_default_subject(), + 'default' => '', + ), + 'subject_partial' => array( + 'title' => _x( 'Partial shipment subject', 'shipments', 'woocommerce-germanized' ), + 'type' => 'text', + 'desc_tip' => true, + 'description' => $placeholder_text, + 'placeholder' => $this->get_default_subject( true ), + 'default' => '', + ), + 'heading_full' => array( + 'title' => _x( 'Full shipment email heading', 'shipments', 'woocommerce-germanized' ), + 'type' => 'text', + 'desc_tip' => true, + 'description' => $placeholder_text, + 'placeholder' => $this->get_default_heading(), + 'default' => '', + ), + 'heading_partial' => array( + 'title' => _x( 'Partial shipment email heading', 'shipments', 'woocommerce-germanized' ), + 'type' => 'text', + 'desc_tip' => true, + 'description' => $placeholder_text, + 'placeholder' => $this->get_default_heading( true ), + 'default' => '', + ), + 'additional_content' => array( + 'title' => _x( 'Additional content', 'shipments', 'woocommerce-germanized' ), + 'description' => _x( 'Text to appear below the main email content.', 'shipments', 'woocommerce-germanized' ) . ' ' . $placeholder_text, + 'css' => 'width:400px; height: 75px;', + 'placeholder' => _x( 'N/A', 'shipments', 'woocommerce-germanized' ), + 'type' => 'textarea', + 'default' => $this->get_default_additional_content(), + 'desc_tip' => true, + ), + 'email_type' => array( + 'title' => _x( 'Email type', 'shipments', 'woocommerce-germanized' ), + 'type' => 'select', + 'description' => _x( 'Choose which format of email to send.', 'shipments', 'woocommerce-germanized' ), + 'default' => 'html', + 'class' => 'email_type wc-enhanced-select', + 'options' => $this->get_email_type_options(), + 'desc_tip' => true, + ), + ); + } + } + +endif; + +return new WC_GZD_Email_Customer_Shipment(); diff --git a/packages/woocommerce-germanized-shipments/includes/emails/class-wc-gzd-email-new-return-shipment-request.php b/packages/woocommerce-germanized-shipments/includes/emails/class-wc-gzd-email-new-return-shipment-request.php new file mode 100644 index 000000000..447beca08 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/includes/emails/class-wc-gzd-email-new-return-shipment-request.php @@ -0,0 +1,221 @@ +id = 'new_return_shipment_request'; + $this->title = _x( 'New order return request', 'shipments', 'woocommerce-germanized' ); + $this->description = _x( 'New order return request emails are sent to chosen recipient(s) when a new return is requested.', 'shipments', 'woocommerce-germanized' ); + + $this->template_html = 'emails/admin-new-return-shipment-request.php'; + $this->template_plain = 'emails/plain/admin-new-return-shipment-request.php'; + $this->template_base = Package::get_path() . '/templates/'; + + $this->placeholders = array( + '{site_title}' => $this->get_blogname(), + '{shipment_number}' => '', + '{order_number}' => '', + '{order_date}' => '', + ); + + // Triggers for this email. + add_action( 'woocommerce_gzd_new_customer_return_shipment_request', array( $this, 'trigger' ), 10 ); + + // Call parent constructor. + parent::__construct(); + + // Other settings. + $this->recipient = $this->get_option( 'recipient', get_option( 'admin_email' ) ); + } + + /** + * Get email subject. + * + * @since 3.1.0 + * @return string + */ + public function get_default_subject() { + return _x( '[{site_title}]: New return request to #{order_number}', 'shipments', 'woocommerce-germanized' ); + } + + /** + * Get email heading. + * + * @since 3.1.0 + * @return string + */ + public function get_default_heading() { + return _x( 'New return request to: #{order_number}', 'shipments', 'woocommerce-germanized' ); + } + + /** + * Trigger. + * + * @param int|ReturnShipment $shipment_id Shipment ID. + */ + public function trigger( $shipment_id ) { + $this->setup_locale(); + + if ( $this->shipment = wc_gzd_get_shipment( $shipment_id ) ) { + + if ( 'return' !== $this->shipment->get_type() ) { + return; + } + + $this->placeholders['{shipment_number}'] = $this->shipment->get_shipment_number(); + + if ( $order_shipment = wc_gzd_get_shipment_order( $this->shipment->get_order() ) ) { + $this->object = $this->shipment->get_order(); + $this->placeholders['{order_date}'] = wc_format_datetime( $order_shipment->get_order()->get_date_created() ); + $this->placeholders['{order_number}'] = $order_shipment->get_order()->get_order_number(); + } + } + + if ( $this->is_enabled() && $this->get_recipient() ) { + $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() ); + } + + $this->restore_locale(); + } + + /** + * Return content from the additional_content field. + * + * Displayed above the footer. + * + * @since 2.0.4 + * @return string + */ + public function get_additional_content() { + if ( is_callable( 'parent::get_additional_content' ) ) { + return parent::get_additional_content(); + } + + return ''; + } + + /** + * Get content html. + * + * @return string + */ + public function get_content_html() { + return wc_get_template_html( + $this->template_html, + array( + 'shipment' => $this->shipment, + 'order' => $this->object, + 'email_heading' => $this->get_heading(), + 'additional_content' => $this->get_additional_content(), + 'sent_to_admin' => true, + 'plain_text' => false, + 'email' => $this, + ) + ); + } + + /** + * Get content plain. + * + * @return string + */ + public function get_content_plain() { + return wc_get_template_html( + $this->template_plain, + array( + 'shipment' => $this->shipment, + 'order' => $this->object, + 'email_heading' => $this->get_heading(), + 'additional_content' => $this->get_additional_content(), + 'sent_to_admin' => true, + 'plain_text' => true, + 'email' => $this, + ) + ); + } + + public function get_attachments() { + $attachments = array(); + + if ( $this->shipment->has_label() ) { + $label = $this->shipment->get_label(); + + if ( $file = $label->get_file() ) { + $attachments[] = $file; + } + } + + return apply_filters( 'woocommerce_email_attachments', $attachments, $this->id, $this->object, $this ); + } + + /** + * Default content to show below main email content. + * + * @since 1.0.1 + * @return string + */ + public function get_default_additional_content() { + return ''; + } + + /** + * Initialise settings form fields. + */ + public function init_form_fields() { + parent::init_form_fields(); + + $this->form_fields = array_merge( + $this->form_fields, + array( + 'recipient' => array( + 'title' => _x( 'Recipient(s)', 'shipments', 'woocommerce-germanized' ), + 'type' => 'text', + /* translators: %s: WP admin email */ + 'description' => sprintf( _x( 'Enter recipients (comma separated) for this email. Defaults to %s.', 'shipments', 'woocommerce-germanized' ), '' . esc_attr( get_option( 'admin_email' ) ) . '' ), + 'placeholder' => '', + 'default' => '', + 'desc_tip' => true, + ), + ) + ); + } + } + +endif; + +return new WC_GZD_Email_New_Return_Shipment_Request(); diff --git a/packages/woocommerce-germanized-shipments/includes/wc-gzd-label-functions.php b/packages/woocommerce-germanized-shipments/includes/wc-gzd-label-functions.php new file mode 100644 index 000000000..1d9785021 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/includes/wc-gzd-label-functions.php @@ -0,0 +1,152 @@ +get_labels(); +} + +function wc_gzd_get_label_type_by_shipment( $shipment ) { + $type = is_a( $shipment, '\Vendidero\Germanized\Shipments\Shipment' ) ? $shipment->get_type() : $shipment; + + return apply_filters( 'woocommerce_gzd_shipment_label_type', $type, $shipment ); +} + +function wc_gzd_get_shipment_label_types() { + return apply_filters( + 'woocommerce_gzd_shipment_label_types', + array( + 'simple', + 'return', + ) + ); +} + +function wc_gzd_get_label_by_shipment( $the_shipment, $type = '' ) { + $shipment_id = \Vendidero\Germanized\Shipments\ShipmentFactory::get_shipment_id( $the_shipment ); + $label = false; + + if ( $shipment_id ) { + $args = array( + 'shipment_id' => $shipment_id, + 'limit' => 1, + ); + + if ( ! empty( $type ) ) { + $args['type'] = $type; + } + + $labels = wc_gzd_get_shipment_labels( $args ); + + if ( ! empty( $labels ) ) { + $label = $labels[0]; + } + } + + return apply_filters( 'woocommerce_gzd_shipment_label_for_shipment', $label, $the_shipment ); +} + +/** + * @param false $the_label + * @param string $shipping_provider + * @param string $type + * + * @return \Vendidero\Germanized\Shipments\Interfaces\ShipmentLabel|boolean + */ +function wc_gzd_get_shipment_label( $the_label = false, $shipping_provider = '', $type = 'simple' ) { + return apply_filters( 'woocommerce_gzd_shipment_label', \Vendidero\Germanized\Shipments\Labels\Factory::get_label( $the_label, $shipping_provider, $type ), $the_label, $shipping_provider, $type ); +} + +/** + * @param \Vendidero\Germanized\Shipments\Shipment $shipment + * @param bool $net_weight + * @param string $unit + * + * @return float + */ +function wc_gzd_get_shipment_label_weight( $shipment, $net_weight = false, $unit = 'kg' ) { + $shipment_weight = $shipment->get_total_weight(); + $shipment_content_weight = $shipment->get_weight(); + $shipment_packaging_weight = $shipment->get_packaging_weight(); + + if ( ! empty( $shipment_weight ) ) { + $shipment_weight = wc_get_weight( $shipment_weight, $unit, $shipment->get_weight_unit() ); + } + + if ( ! empty( $shipment_content_weight ) ) { + $shipment_content_weight = wc_get_weight( $shipment_content_weight, $unit, $shipment->get_weight_unit() ); + } + + if ( ! empty( $shipment_packaging_weight ) ) { + $shipment_packaging_weight = wc_get_weight( $shipment_packaging_weight, $unit, $shipment->get_weight_unit() ); + } + + /** + * The net weight does not include packaging weight. + */ + if ( $net_weight ) { + $shipment_packaging_weight = 0; + $shipment_weight = $shipment_content_weight; + } + + if ( $provider = $shipment->get_shipping_provider_instance() ) { + $min_weight = wc_get_weight( $provider->get_shipment_setting( $shipment, 'label_minimum_shipment_weight' ), $unit, 'kg' ); + $default_weight = wc_get_weight( $provider->get_shipment_setting( $shipment, 'label_default_shipment_weight' ), $unit, 'kg' ); + + if ( empty( $shipment_content_weight ) ) { + $shipment_weight = $default_weight; + + if ( ! $net_weight ) { + $shipment_weight += $shipment_packaging_weight; + } + } + + if ( $shipment_weight < $min_weight ) { + $shipment_weight = $min_weight; + } + } + + $shipment_weight = wc_format_decimal( $shipment_weight, 2 ); + + return apply_filters( 'woocommerce_gzd_shipment_label_weight', $shipment_weight, $shipment, $unit ); +} + +/** + * @param \Vendidero\Germanized\Shipments\Shipment $shipment + * @param string $dimension + * @param string $unit + */ +function wc_gzd_get_shipment_label_dimensions( $shipment, $unit = 'cm' ) { + $dimensions = array( + 'length' => 0, + 'width' => 0, + 'height' => 0, + ); + + if ( $shipment->has_dimensions() ) { + $dimensions = $shipment->get_package_dimensions(); + + foreach ( $dimensions as $key => $data ) { + $dimensions[ $key ] = wc_get_dimension( $data, $unit, $shipment->get_dimension_unit() ); + } + } + + return apply_filters( 'woocommerce_gzd_shipment_label_dimensions', $dimensions, $shipment, $unit ); +} diff --git a/packages/woocommerce-germanized-shipments/includes/wc-gzd-packaging-functions.php b/packages/woocommerce-germanized-shipments/includes/wc-gzd-packaging-functions.php new file mode 100644 index 000000000..6d949f7d2 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/includes/wc-gzd-packaging-functions.php @@ -0,0 +1,60 @@ + _x( 'Cardboard', 'shipments', 'woocommerce-germanized' ), + 'letter' => _x( 'Letter', 'shipments', 'woocommerce-germanized' ), + ); + + return apply_filters( 'woocommerce_gzd_packaging_types', $types ); +} + +/** + * @return \Vendidero\Germanized\Shipments\Packaging[] $packaging_list + */ +function wc_gzd_get_packaging_list() { + $data_store = \WC_Data_Store::load( 'packaging' ); + $list = $data_store->get_packaging_list(); + + return $list; +} + +function wc_gzd_get_packaging_weight_unit() { + return apply_filters( 'woocommerce_gzd_packaging_weight_unit', 'kg' ); +} + +function wc_gzd_get_packaging_dimension_unit() { + return apply_filters( 'woocommerce_gzd_packaging_dimension_unit', 'cm' ); +} + +function wc_gzd_get_packaging_select() { + $list = wc_gzd_get_packaging_list(); + $select = array( + '' => _x( 'None', 'shipments-packaging', 'woocommerce-germanized' ), + ); + + foreach ( $list as $packaging ) { + $select[ $packaging->get_id() ] = $packaging->get_title(); + } + + return $select; +} diff --git a/packages/woocommerce-germanized-shipments/includes/wc-gzd-shipment-functions.php b/packages/woocommerce-germanized-shipments/includes/wc-gzd-shipment-functions.php new file mode 100644 index 000000000..6ccfde268 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/includes/wc-gzd-shipment-functions.php @@ -0,0 +1,1463 @@ +countries ? WC()->countries->get_states( $country ) : array(); + $formatted_state = ( $states && isset( $states[ $state ] ) ) ? $states[ $state ] : $state; + + return $formatted_state; +} + +function wc_gzd_get_shipment_order( $order ) { + if ( is_numeric( $order ) ) { + $order = wc_get_order( $order ); + } + + if ( is_a( $order, 'WC_Order' ) ) { + try { + return new Vendidero\Germanized\Shipments\Order( $order ); + } catch ( Exception $e ) { + wc_caught_exception( $e, __FUNCTION__, array( $order ) ); + return false; + } + } + + return false; +} + +function wc_gzd_get_shipment_label_title( $type, $plural = false ) { + $type_data = wc_gzd_get_shipment_type_data( $type ); + + return ( ! $plural ? $type_data['labels']['singular'] : $type_data['labels']['plural'] ); +} + +function wc_gzd_get_shipment_types() { + return array_keys( wc_gzd_get_shipment_type_data( false ) ); +} + +/** + * Get shipment type data by type. + * + * @param string $type type name. + * @return bool|array Details about the shipment type. + * + * @package Vendidero/Germanized/Shipments + */ +function wc_gzd_get_shipment_type_data( $type = false ) { + $types = apply_filters( + 'woocommerce_gzd_shipment_type_data', + array( + 'simple' => array( + 'class_name' => '\Vendidero\Germanized\Shipments\SimpleShipment', + 'labels' => array( + 'singular' => _x( 'Shipment', 'shipments', 'woocommerce-germanized' ), + 'plural' => _x( 'Shipments', 'shipments', 'woocommerce-germanized' ), + ), + ), + 'return' => array( + 'class_name' => '\Vendidero\Germanized\Shipments\ReturnShipment', + 'labels' => array( + 'singular' => _x( 'Return', 'shipments', 'woocommerce-germanized' ), + 'plural' => _x( 'Returns', 'shipments', 'woocommerce-germanized' ), + ), + ), + ) + ); + + if ( $type && array_key_exists( $type, $types ) ) { + return $types[ $type ]; + } elseif ( false === $type ) { + return $types; + } else { + return $types['simple']; + } +} + +function wc_gzd_get_shipments_by_order( $order ) { + $shipments = array(); + + if ( $order_shipment = wc_gzd_get_shipment_order( $order ) ) { + $shipments = $order_shipment->get_shipments(); + } + + return $shipments; +} + +function wc_gzd_get_shipment_order_shipping_statuses() { + $shipment_statuses = array( + 'gzd-not-shipped' => _x( 'Not shipped', 'shipments', 'woocommerce-germanized' ), + 'gzd-partially-shipped' => _x( 'Partially shipped', 'shipments', 'woocommerce-germanized' ), + 'gzd-shipped' => _x( 'Shipped', 'shipments', 'woocommerce-germanized' ), + 'gzd-partially-delivered' => _x( 'Partially delivered', 'shipments', 'woocommerce-germanized' ), + 'gzd-delivered' => _x( 'Delivered', 'shipments', 'woocommerce-germanized' ), + 'gzd-no-shipping-needed' => _x( 'No shipping needed', 'shipments', 'woocommerce-germanized' ), + ); + + /** + * Filter to adjust or add order shipping statuses. + * An order might retrieve a shipping status e.g. not shipped. + * + * @param array $shipment_statuses Available order shipping statuses. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_order_shipping_statuses', $shipment_statuses ); +} + +function wc_gzd_get_shipment_order_return_statuses() { + $shipment_statuses = array( + 'gzd-open' => _x( 'Open', 'shipments', 'woocommerce-germanized' ), + 'gzd-partially-returned' => _x( 'Partially returned', 'shipments', 'woocommerce-germanized' ), + 'gzd-returned' => _x( 'Returned', 'shipments', 'woocommerce-germanized' ), + ); + + /** + * Filter to adjust or add order return statuses. + * An order might retrieve a shipping status e.g. not shipped. + * + * @param array $shipment_statuses Available order return statuses. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_order_return_statuses', $shipment_statuses ); +} + +/** + * @param $instance_id + * + * @return ShippingProvider\Method + */ +function wc_gzd_get_shipping_provider_method( $instance_id ) { + $original_id = $instance_id; + + if ( is_a( $original_id, 'WC_Shipping_Rate' ) ) { + $instance_id = $original_id->get_instance_id(); + } elseif ( is_a( $original_id, 'WC_Shipping_Method' ) ) { + $instance_id = $original_id->get_instance_id(); + } elseif ( ! is_numeric( $instance_id ) && is_string( $instance_id ) ) { + if ( strpos( $instance_id, ':' ) !== false ) { + $expl = explode( ':', $instance_id ); + $instance_id = ( ( ! empty( $expl ) && count( $expl ) > 1 ) ? (int) $expl[1] : 0 ); + } else { + /** + * Plugins like Flexible Shipping use underscores to separate instance ids. + * Example: flexible_shipping_4_1. In this case, 4 ist the instance id. Let's find out. + */ + $expl = explode( '_', $instance_id ); + $numbers = array_values( array_filter( $expl, 'is_numeric' ) ); + + if ( ! empty( $numbers ) ) { + $instance_id = absint( $numbers[0] ); + } + } + } + + if ( ! empty( $instance_id ) ) { + // Make sure shipping zones are loaded + include_once WC_ABSPATH . 'includes/class-wc-shipping-zones.php'; + + /** + * Cache methods within frontend + */ + if ( WC()->session && did_action( 'woocommerce_shipping_init' ) ) { + $cache_key = 'woocommerce_gzd_method_' . $instance_id; + $tmp_method = WC()->session->get( $cache_key ); + + if ( ! $tmp_method || ! is_object( $tmp_method ) || is_a( $tmp_method, '__PHP_Incomplete_Class' ) ) { + $method = WC_Shipping_Zones::get_shipping_method( $instance_id ); + + if ( $method ) { + WC()->session->set( $cache_key, $method ); + } + } else { + $method = $tmp_method; + } + } else { + $method = WC_Shipping_Zones::get_shipping_method( $instance_id ); + } + + if ( $method ) { + /** + * Filter to adjust the classname used to construct the shipping provider method + * which contains additional provider related settings useful for shipments. + * + * @param string $classname The classname. + * @param WC_Shipping_Method $method The shipping method instance. + * + * @since 3.0.6 + * @package Vendidero/Germanized/Shipments + */ + $classname = apply_filters( 'woocommerce_gzd_shipping_provider_method_classname', 'Vendidero\Germanized\Shipments\ShippingProvider\Method', $method ); + + return new $classname( $method ); + } + } + + // Load placeholder + $placeholder = new ShippingProvider\MethodPlaceholder( $original_id ); + + /** + * Filter to adjust the fallback shipping method to be loaded if no real + * shipping method was able to be constructed (e.g. a custom plugin is being used which + * replaces the default Woo shipping zones integration). + * + * @param ShippingProvider\MethodPlaceholder $placeholder The placeholder impl. + * @param string $original_id The shipping method id. + * + * @since 3.0.6 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipping_provider_method_fallback', $placeholder, $original_id ); +} + +/** + * Returns the current shipping method rate id. + * + * @return false|string + */ +function wc_gzd_get_current_shipping_method_id() { + $chosen_shipping_methods = WC()->session ? WC()->session->get( 'chosen_shipping_methods' ) : array(); + + if ( ! empty( $chosen_shipping_methods ) ) { + return reset( $chosen_shipping_methods ); + } + + return false; +} + +function wc_gzd_get_current_shipping_provider_method() { + if ( $current = wc_gzd_get_current_shipping_method_id() ) { + return wc_gzd_get_shipping_provider_method( $current ); + } + + return false; +} + +function wc_gzd_get_shipment_order_shipping_status_name( $status ) { + if ( 'gzd-' !== substr( $status, 0, 4 ) ) { + $status = 'gzd-' . $status; + } + + $status_name = ''; + $statuses = wc_gzd_get_shipment_order_shipping_statuses(); + + if ( array_key_exists( $status, $statuses ) ) { + $status_name = $statuses[ $status ]; + } + + /** + * Filter to adjust the status name for a certain order shipping status. + * + * @see wc_gzd_get_shipment_order_shipping_statuses() + * + * @param string $status_name The status name. + * @param string $status The shipping status. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_order_shipping_status_name', $status_name, $status ); +} + +function wc_gzd_get_shipment_order_return_status_name( $status ) { + if ( 'gzd-' !== substr( $status, 0, 4 ) ) { + $status = 'gzd-' . $status; + } + + $status_name = ''; + $statuses = wc_gzd_get_shipment_order_return_statuses(); + + if ( array_key_exists( $status, $statuses ) ) { + $status_name = $statuses[ $status ]; + } + + /** + * Filter to adjust the status name for a certain order return status. + * + * @see wc_gzd_get_shipment_order_return_statuses() + * + * @param string $status_name The status name. + * @param string $status The return status. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_order_return_status_name', $status_name, $status ); +} + +/** + * Standard way of retrieving shipments based on certain parameters. + * + * @param array $args Array of args (above). + * + * @return Shipment[] The shipments found. + *@since 3.0.0 + */ +function wc_gzd_get_shipments( $args ) { + $query = new Vendidero\Germanized\Shipments\ShipmentQuery( $args ); + + return $query->get_shipments(); +} + +function wc_gzd_get_shipment_customer_visible_statuses( $shipment_type = 'simple' ) { + $statuses = array_keys( wc_gzd_get_shipment_statuses() ); + $statuses = array_diff( $statuses, array( 'gzd-draft' ) ); + + /** + * Filter to decide which shipment statuses should be visible to customers + * e.g. whether a shipment of a certain status should be shown or not. + * + * @param array $shipment_statuses The available shipment statuses. + * @param string $shipment_type The shipment type. + * + * @since 3.1.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipment_customer_visible_statuses', $statuses, $shipment_type ); +} + +/** + * Main function for returning shipments. + * + * @param mixed $the_shipment Object or shipment id. + * + * @return bool|SimpleShipment|ReturnShipment|Shipment + */ +function wc_gzd_get_shipment( $the_shipment ) { + return ShipmentFactory::get_shipment( $the_shipment ); +} + +/** + * Get all shipment statuses. + * + * @return array + */ +function wc_gzd_get_shipment_statuses() { + $shipment_statuses = array( + 'gzd-draft' => _x( 'Draft', 'shipments', 'woocommerce-germanized' ), + 'gzd-processing' => _x( 'Processing', 'shipments', 'woocommerce-germanized' ), + 'gzd-shipped' => _x( 'Shipped', 'shipments', 'woocommerce-germanized' ), + 'gzd-delivered' => _x( 'Delivered', 'shipments', 'woocommerce-germanized' ), + 'gzd-requested' => _x( 'Requested', 'shipments', 'woocommerce-germanized' ), + ); + + /** + * Add or adjust available Shipment statuses. + * + * @param array $shipment_statuses The available shipment statuses. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipment_statuses', $shipment_statuses ); +} + +/** + * @param Shipment $shipment + * + * @return mixed|void + */ +function wc_gzd_get_shipment_selectable_statuses( $shipment ) { + $shipment_statuses = wc_gzd_get_shipment_statuses(); + + if ( ! $shipment->has_status( 'requested' ) && isset( $shipment_statuses['gzd-requested'] ) ) { + unset( $shipment_statuses['gzd-requested'] ); + } + + /** + * Add or remove selectable shipment statuses for a certain shipment and/or shipment type. + * + * @param array $shipment_statuses The available shipment statuses. + * @param string $type The shipment type e.g. return. + * @param Shipment $shipment The shipment instance. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipment_selectable_statuses', $shipment_statuses, $shipment->get_type(), $shipment ); +} + +/** + * @param Order $order_shipment + * @param array $args + * + * @return ReturnShipment|WP_Error + */ +function wc_gzd_create_return_shipment( $order_shipment, $args = array() ) { + try { + + if ( ! $order_shipment || ! is_a( $order_shipment, 'Vendidero\Germanized\Shipments\Order' ) ) { + throw new Exception( _x( 'Invalid order.', 'shipments', 'woocommerce-germanized' ) ); + } + + if ( ! $order_shipment->needs_return() ) { + throw new Exception( _x( 'This order is already fully returned.', 'shipments', 'woocommerce-germanized' ) ); + } + + $args = wp_parse_args( + $args, + array( + 'items' => array(), + 'props' => array(), + ) + ); + + $shipment = ShipmentFactory::get_shipment( false, 'return' ); + + if ( ! $shipment ) { + throw new Exception( _x( 'Error while creating the shipment instance', 'shipments', 'woocommerce-germanized' ) ); + } + + // Make sure shipment knows its parent + $shipment->set_order_shipment( $order_shipment ); + $shipment->sync( $args['props'] ); + $shipment->sync_items( $args ); + $shipment->save(); + + } catch ( Exception $e ) { + return new WP_Error( 'error', $e->getMessage() ); + } + + return $shipment; +} + +/** + * @param Order $order_shipment + * @param array $args + * + * @return Shipment|WP_Error + */ +function wc_gzd_create_shipment( $order_shipment, $args = array() ) { + try { + + if ( ! $order_shipment || ! is_a( $order_shipment, 'Vendidero\Germanized\Shipments\Order' ) ) { + throw new Exception( _x( 'Invalid shipment order', 'shipments', 'woocommerce-germanized' ) ); + } + + if ( ! $order = $order_shipment->get_order() ) { + throw new Exception( _x( 'Invalid shipment order', 'shipments', 'woocommerce-germanized' ) ); + } + + $args = wp_parse_args( + $args, + array( + 'items' => array(), + 'props' => array(), + ) + ); + + $shipment = ShipmentFactory::get_shipment( false, 'simple' ); + + if ( ! $shipment ) { + throw new Exception( _x( 'Error while creating the shipment instance', 'shipments', 'woocommerce-germanized' ) ); + } + + $shipment->set_order_shipment( $order_shipment ); + $shipment->sync( $args['props'] ); + $shipment->sync_items( $args ); + $shipment->save(); + + } catch ( Exception $e ) { + return new WP_Error( 'error', $e->getMessage() ); + } + + return $shipment; +} + +function wc_gzd_create_shipment_item( $shipment, $order_item, $args = array() ) { + try { + + if ( ! $order_item || ! is_a( $order_item, 'WC_Order_Item' ) ) { + throw new Exception( _x( 'Invalid order item', 'shipments', 'woocommerce-germanized' ) ); + } + + $item = new Vendidero\Germanized\Shipments\ShipmentItem(); + + $item->set_order_item_id( $order_item->get_id() ); + $item->set_shipment( $shipment ); + $item->sync( $args ); + $item->save(); + + } catch ( Exception $e ) { + return new WP_Error( 'error', $e->getMessage() ); + } + + return $item; +} + +function wc_gzd_allow_customer_return_empty_return_reason( $order ) { + return apply_filters( 'woocommerce_gzd_allow_customer_return_empty_return_reason', true, $order ); +} + +/** + * @param bool $allow_none + * @param bool|WC_Order_Item $order_item + * + * @return ReturnReason[] + */ +function wc_gzd_get_return_shipment_reasons( $order_item = false ) { + $reasons = Package::get_setting( 'return_reasons' ); + + if ( ! is_array( $reasons ) ) { + $reasons = array(); + } else { + $reasons = array_filter( $reasons ); + } + + /** + * Filter that allows adjusting raw return reasons for a specific shipment (e.g. array containing reason data with code, reason and order). + * + * @param array $reasons Available return reasons. + * @param WC_Order_Item|false $order_item The order item object if available to further filter reasons. + * + * @since 3.1.0 + * @package Vendidero/Germanized/Shipments + */ + $reasons = apply_filters( 'woocommerce_gzd_return_shipment_reasons_raw', $reasons, $order_item ); + $instances = array(); + + foreach ( $reasons as $reason ) { + $instances[] = new ReturnReason( $reason ); + } + + usort( $instances, '_wc_gzd_sort_return_shipment_reasons' ); + + /** + * Filter that allows to adjust available return reasons for a specific shipment. + * + * @param ReturnReason[] $reasons Available return reasons. + * @param WC_Order_Item|false $order_item The order item object if available to further filter reasons. + * + * @since 3.1.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_return_shipment_reasons', $instances, $order_item ); +} + +function wc_gzd_return_shipment_reason_exists( $maybe_reason, $shipment = false ) { + $reasons = wc_gzd_get_return_shipment_reasons( $shipment ); + $exists = false; + + foreach ( $reasons as $reason ) { + + if ( $reason->get_code() === $maybe_reason ) { + $exists = true; + break; + } + } + + return $exists; +} + +/** + * @param ReturnReason $a + * @param ReturnReason $b + */ +function _wc_gzd_sort_return_shipment_reasons( $a, $b ) { + if ( $a->get_order() === $b->get_order() ) { + return 0; + } elseif ( $a->get_order() > $b->get_order() ) { + return 1; + } else { + return -1; + } +} + +/** + * @param WP_Error $error + * + * @return bool + */ +function wc_gzd_shipment_wp_error_has_errors( $error ) { + if ( is_callable( array( $error, 'has_errors' ) ) ) { + return $error->has_errors(); + } else { + $errors = $error->errors; + + return ( ! empty( $errors ) ? true : false ); + } +} + +/** + * @param Shipment $shipment + * @param ShipmentItem $shipment_item + * @param array $args + * + * @return ShipmentReturnItem|WP_Error + */ +function wc_gzd_create_return_shipment_item( $shipment, $shipment_item, $args = array() ) { + + try { + + if ( ! $shipment_item || ! is_a( $shipment_item, '\Vendidero\Germanized\Shipments\ShipmentItem' ) ) { + throw new Exception( _x( 'Invalid shipment item', 'shipments', 'woocommerce-germanized' ) ); + } + + $item = new Vendidero\Germanized\Shipments\ShipmentReturnItem(); + $item->set_order_item_id( $shipment_item->get_order_item_id() ); + $item->set_shipment( $shipment ); + $item->sync( $args ); + $item->save(); + + } catch ( Exception $e ) { + return new WP_Error( 'error', $e->getMessage() ); + } + + return $item; +} + +function wc_gzd_get_shipment_editable_statuses() { + /** + * Filter that allows to adjust Shipment statuses which decide upon whether + * a Shipment is editable or not. + * + * @param array $statuses Statuses which should be considered as editable. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipment_editable_statuses', array( 'draft', 'requested', 'processing' ) ); +} + +function wc_gzd_split_shipment_street( $street_str ) { + $return = array( + 'street' => $street_str, + 'number' => '', + 'addition' => '', + 'addition_2' => '', + ); + + try { + $split = AddressSplitter::split_address( $street_str ); + + $return['street'] = $split['streetName']; + $return['number'] = $split['houseNumber']; + /** + * e.g. 5. OG + */ + $return['addition'] = isset( $split['additionToAddress2'] ) ? $split['additionToAddress2'] : ''; + /** + * E.g. details to the location prefixed to the street name + */ + $return['addition_2'] = isset( $split['additionToAddress1'] ) ? $split['additionToAddress1'] : ''; + } catch ( Exception $e ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch + } + + return $return; +} + +function wc_gzd_get_shipping_providers() { + return ShippingProvider\Helper::instance()->get_shipping_providers(); +} + +function wc_gzd_get_shipping_provider( $name ) { + return ShippingProvider\Helper::instance()->get_shipping_provider( $name ); +} + +function wc_gzd_get_default_shipping_provider() { + $default = Package::get_setting( 'default_shipping_provider' ); + + /** + * Filter to adjust the default shipping provider used as a fallback for shipments + * for which no provider could be determined automatically (e.g. by the chosen shipping methid). + * + * @param string $title The shipping provider slug. + * + * @since 3.0.6 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_default_shipping_provider', $default ); +} + +function wc_gzd_get_shipping_provider_select() { + $providers = wc_gzd_get_shipping_providers(); + $select = array( + '' => _x( 'None', 'shipments', 'woocommerce-germanized' ), + ); + + foreach ( $providers as $provider ) { + if ( ! $provider->is_activated() ) { + continue; + } + $select[ $provider->get_name() ] = $provider->get_title(); + } + + return $select; +} + +function wc_gzd_get_shipping_provider_title( $slug ) { + $providers = wc_gzd_get_shipping_providers(); + + if ( array_key_exists( $slug, $providers ) ) { + $title = $providers[ $slug ]->get_title(); + } else { + $title = $slug; + } + + /** + * Filter to adjust the title of a certain shipping provider e.g. DHL. + * + * @param string $title The shipping provider title. + * @param string $slug The shipping provider slug. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipping_provider_title', $title, $slug ); +} + +/** + * @param Shipment $shipment + */ +function wc_gzd_get_shipment_shipping_provider_title( $shipment ) { + $title = $shipment->get_shipping_provider_title(); + + if ( empty( $title ) ) { + $title = apply_filters( 'woocommerce_gzd_shipping_provider_unknown_title', _x( 'Unknown', 'shipments-shipping-provider', 'woocommerce-germanized' ) ); + } + + return $title; +} + +function wc_gzd_get_shipping_provider_slug( $provider ) { + $providers = wc_gzd_get_shipping_providers(); + + if ( in_array( $provider, $providers, true ) ) { + $slug = array_search( $provider, $providers, true ); + } elseif ( array_key_exists( $provider, $providers ) ) { + $slug = $provider; + } else { + $slug = sanitize_key( $provider ); + } + + return $slug; +} + +function _wc_gzd_shipments_keep_force_filename( $new_filename ) { + return isset( $GLOBALS['gzd_shipments_unique_filename'] ) ? $GLOBALS['gzd_shipments_unique_filename'] : $new_filename; +} + +function wc_gzd_shipments_upload_data( $filename, $bits, $relative = true ) { + try { + Package::set_upload_dir_filter(); + $GLOBALS['gzd_shipments_unique_filename'] = $filename; + add_filter( 'wp_unique_filename', '_wc_gzd_shipments_keep_force_filename', 10, 1 ); + + $tmp = wp_upload_bits( $filename, null, $bits ); + + unset( $GLOBALS['gzd_shipments_unique_filename'] ); + remove_filter( 'wp_unique_filename', '_wc_gzd_shipments_keep_force_filename', 10 ); + Package::unset_upload_dir_filter(); + + if ( isset( $tmp['file'] ) ) { + $path = $tmp['file']; + + if ( $relative ) { + $path = Package::get_relative_upload_dir( $path ); + } + + return $path; + } else { + throw new Exception( _x( 'Error while uploading file.', 'shipments', 'woocommerce-germanized' ) ); + } + } catch ( Exception $e ) { + return false; + } +} + +function wc_gzd_get_shipment_setting_default_address_fields( $type = 'shipper' ) { + $address_fields = array( + 'first_name' => _x( 'First Name', 'shipments', 'woocommerce-germanized' ), + 'last_name' => _x( 'Last Name', 'shipments', 'woocommerce-germanized' ), + 'full_name' => _x( 'Full Name', 'shipments', 'woocommerce-germanized' ), + 'company' => _x( 'Company', 'shipments', 'woocommerce-germanized' ), + 'address_1' => _x( 'Address 1', 'shipments', 'woocommerce-germanized' ), + 'address_2' => _x( 'Address 2', 'shipments', 'woocommerce-germanized' ), + 'street' => _x( 'Street', 'shipments', 'woocommerce-germanized' ), + 'street_number' => _x( 'House Number', 'shipments', 'woocommerce-germanized' ), + 'postcode' => _x( 'Postcode', 'shipments', 'woocommerce-germanized' ), + 'city' => _x( 'City', 'shipments', 'woocommerce-germanized' ), + 'country' => _x( 'Country', 'shipments', 'woocommerce-germanized' ), + 'state' => _x( 'State', 'shipments', 'woocommerce-germanized' ), + 'phone' => _x( 'Phone', 'shipments', 'woocommerce-germanized' ), + 'email' => _x( 'Email', 'shipments', 'woocommerce-germanized' ), + 'customs_reference_number' => _x( 'Customs Reference Number', 'shipments', 'woocommerce-germanized' ), + ); + + return apply_filters( 'woocommerce_gzd_shipment_default_address_fields', $address_fields, $type ); +} + +/** + * @return array + */ +function wc_gzd_get_shipment_setting_address_fields( $address_type = 'shipper' ) { + $default_address_fields = array_keys( wc_gzd_get_shipment_setting_default_address_fields( $address_type ) ); + $default_address_data = array(); + + if ( 'return' === $address_type ) { + $default_address_data = wc_gzd_get_shipment_setting_address_fields( 'shipper' ); + } + + foreach ( $default_address_fields as $prop ) { + $key = "woocommerce_gzd_shipments_{$address_type}_address_{$prop}"; + $value = get_option( $key, '' ); + + if ( '' === $value && array_key_exists( $prop, $default_address_data ) ) { + $value = $default_address_data[ $prop ]; + } + + $address_fields[ $prop ] = $value; + } + + if ( ! empty( $address_fields['country'] ) && strlen( $address_fields['country'] ) > 2 ) { + $value = wc_format_country_state_string( $address_fields['country'] ); + $address_fields['country'] = $value['country']; + $address_fields['state'] = $value['state']; + } + + /** + * Format/split address 1 into street and house number + */ + if ( ! empty( $address_fields['address_1'] ) ) { + $split = wc_gzd_split_shipment_street( $address_fields['address_1'] ); + + $address_fields['street'] = $split['street']; + $address_fields['street_number'] = $split['number']; + } else { + $address_fields['street'] = ''; + $address_fields['street_number'] = ''; + } + + /** + * Attach formatted full name + */ + $address_fields['full_name'] = trim( sprintf( _x( '%1$s %2$s', 'full name', 'woocommerce-germanized' ), $address_fields['first_name'], $address_fields['last_name'] ) ); + + return apply_filters( "woocommerce_gzd_shipment_{$address_type}_address_fields", $address_fields, $address_type ); +} + +/** + * @param Order $shipment_order + * + * @return array + */ +function wc_gzd_get_shipment_return_address( $shipment_order = false ) { + return wc_gzd_get_shipment_setting_address_fields( 'return' ); +} + +/** + * @param WC_Order $order + */ +function wc_gzd_get_shipment_order_shipping_method_id( $order ) { + $methods = $order->get_shipping_methods(); + $id = ''; + + if ( ! empty( $methods ) ) { + $method_vals = array_values( $methods ); + $method = array_shift( $method_vals ); + + if ( $method ) { + $id = $method->get_method_id() . ':' . $method->get_instance_id(); + } + } + + /** + * Allows adjusting the shipping method id for a certain Order. + * + * @param string $id The shipping method id. + * @param WC_Order $order The order object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipment_order_shipping_method_id', $id, $order ); +} + +function wc_gzd_render_shipment_action_buttons( $actions ) { + $actions_html = ''; + + foreach ( $actions as $action ) { + if ( isset( $action['group'] ) ) { + $actions_html .= '
' . wc_gzd_render_shipment_action_buttons( $action['actions'] ) . '
'; + } elseif ( isset( $action['action'], $action['url'], $action['name'] ) ) { + $target = isset( $action['target'] ) ? $action['target'] : '_self'; + + $actions_html .= sprintf( '%5$s', esc_attr( $action['action'] ), esc_url( $action['url'] ), esc_attr( isset( $action['title'] ) ? $action['title'] : $action['name'] ), $target, esc_html( $action['name'] ) ); + } + } + + return $actions_html; +} + +function wc_gzd_get_shipment_status_name( $status ) { + if ( 'gzd-' !== substr( $status, 0, 4 ) ) { + $status = 'gzd-' . $status; + } + + $status_name = ''; + $statuses = wc_gzd_get_shipment_statuses(); + + if ( array_key_exists( $status, $statuses ) ) { + $status_name = $statuses[ $status ]; + } + + /** + * Filter to adjust the shipment status name or title. + * + * @param string $status_name The status name or title. + * @param integer $status The status slug. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipment_status_name', $status_name, $status ); +} + +function wc_gzd_get_shipment_sent_statuses() { + /** + * Filter to adjust which Shipment statuses should be considered as sent. + * + * @param array $statuses An array of statuses considered as shipped, + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( + 'woocommerce_gzd_shipment_sent_statuses', + array( + 'shipped', + 'delivered', + ) + ); +} + +function wc_gzd_get_shipment_counts( $type = '' ) { + $counts = array(); + + foreach ( array_keys( wc_gzd_get_shipment_statuses() ) as $status ) { + $counts[ $status ] = wc_gzd_get_shipment_count( $status, $type ); + } + + return $counts; +} + +function wc_gzd_get_shipment_count( $status, $type = '' ) { + $count = 0; + $status = ( substr( $status, 0, 4 ) ) === 'gzd-' ? $status : 'gzd-' . $status; + $shipment_statuses = array_keys( wc_gzd_get_shipment_statuses() ); + + if ( ! in_array( $status, $shipment_statuses, true ) ) { + return 0; + } + + $cache_key = WC_Cache_Helper::get_cache_prefix( 'shipments' ) . $status . $type; + $cached_count = wp_cache_get( $cache_key, 'counts' ); + + if ( false !== $cached_count ) { + return $cached_count; + } + + $data_store = WC_Data_Store::load( 'shipment' ); + + if ( $data_store ) { + $count += $data_store->get_shipment_count( $status, $type ); + } + + wp_cache_set( $cache_key, $count, 'counts' ); + + return $count; +} + +/** + * See if a string is a shipment status. + * + * @param string $maybe_status Status, including any gzd- prefix. + * @return bool + */ +function wc_gzd_is_shipment_status( $maybe_status ) { + $shipment_statuses = wc_gzd_get_shipment_statuses(); + + return isset( $shipment_statuses[ $maybe_status ] ); +} + +/** + * Main function for returning shipment items. + * + * @since 2.2 + * + * @param mixed $the_item Object or shipment item id. + * @param string $item_type The shipment item type. + * + * @return bool|ShipmentItem + */ +function wc_gzd_get_shipment_item( $the_item = false, $item_type = 'simple' ) { + $item_id = wc_gzd_get_shipment_item_id( $the_item ); + + if ( ! $item_id ) { + return false; + } + + $item_class = 'Vendidero\Germanized\Shipments\ShipmentItem'; + + if ( 'return' === $item_type ) { + $item_class = 'Vendidero\Germanized\Shipments\ShipmentReturnItem'; + } + + /** + * Filter to adjust the classname used to construct a ShipmentItem. + * + * @param string $classname The classname to be used. + * @param integer $item_id The shipment item id. + * @param string $item_type The shipment item type. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + $classname = apply_filters( 'woocommerce_gzd_shipment_item_class', $item_class, $item_id, $item_type ); + + if ( ! class_exists( $classname ) ) { + return false; + } + + try { + return new $classname( $item_id ); + } catch ( Exception $e ) { + wc_caught_exception( $e, __FUNCTION__, array( $the_item, $item_type ) ); + return false; + } +} + +/** + * Get the shipment item ID depending on what was passed. + * + * @since 3.0.0 + * @param mixed $item Item data to convert to an ID. + * @return int|bool false on failure + */ +function wc_gzd_get_shipment_item_id( $item ) { + if ( is_numeric( $item ) ) { + return $item; + } elseif ( $item instanceof Vendidero\Germanized\Shipments\ShipmentItem ) { + return $item->get_id(); + } elseif ( ! empty( $item->shipment_item_id ) ) { + return $item->shipment_item_id; + } else { + return false; + } +} + +/** + * Format dimensions for display. + * + * @since 3.0.0 + * @param array $dimensions Array of dimensions. + * @return string + */ +function wc_gzd_format_shipment_dimensions( $dimensions, $unit = '' ) { + $dimension_string = implode( ' × ', array_filter( array_map( 'wc_format_localized_decimal', $dimensions ) ) ); + + if ( ! empty( $dimension_string ) ) { + $unit = empty( $unit ) ? get_option( 'woocommerce_dimension_unit' ) : $unit; + $dimension_string .= ' ' . $unit; + } else { + $dimension_string = _x( 'N/A', 'shipments', 'woocommerce-germanized' ); + } + + /** + * Filter to adjust the format of Shipment dimensions e.g. LxBxH. + * + * @param string $dimension_string The dimension string. + * @param array $dimensions Array containing the dimensions. + * @param string $unit The dimension unit. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_format_shipment_dimensions', $dimension_string, $dimensions, $unit ); +} + +/** + * Format a weight for display. + * + * @since 3.0.0 + * @param float $weight Weight. + * @return string + */ +function wc_gzd_format_shipment_weight( $weight, $unit = '' ) { + $weight_string = wc_format_localized_decimal( $weight ); + + if ( ! empty( $weight_string ) ) { + $unit = empty( $unit ) ? get_option( 'woocommerce_weight_unit' ) : $unit; + $weight_string .= ' ' . $unit; + } else { + $weight_string = _x( 'N/A', 'shipments', 'woocommerce-germanized' ); + } + + /** + * Filter to adjust the format of Shipment weight. + * + * @param string $weight_string The weight string. + * @param string $weight The Shipment weight. + * @param string $unit The dimension unit. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_format_shipment_weight', $weight_string, $weight, $unit ); +} + +/** + * Get My Account > Shipments columns. + * + * @since 3.0.0 + * @return array + */ +function wc_gzd_get_account_shipments_columns( $type = 'simple' ) { + /** + * Filter to adjust columns being used to display shipments in a table view on the customer + * account page. + * + * @param string[] $columns The columns in key => value pairs. + * @param string $type The shipment type e.g. simple or return. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + $columns = apply_filters( + 'woocommerce_gzd_account_shipments_columns', + array( + 'shipment-number' => _x( 'Shipment', 'shipments', 'woocommerce-germanized' ), + 'shipment-date' => _x( 'Date', 'shipments', 'woocommerce-germanized' ), + 'shipment-status' => _x( 'Status', 'shipments', 'woocommerce-germanized' ), + 'shipment-tracking' => _x( 'Tracking', 'shipments', 'woocommerce-germanized' ), + 'shipment-actions' => _x( 'Actions', 'shipments', 'woocommerce-germanized' ), + ), + $type + ); + + return $columns; +} + +function wc_gzd_get_order_customer_add_return_url( $order ) { + + if ( ! $shipment_order = wc_gzd_get_shipment_order( $order ) ) { + return false; + } + + $url = wc_get_endpoint_url( 'add-return-shipment', $shipment_order->get_order()->get_id(), wc_get_page_permalink( 'myaccount' ) ); + + if ( $shipment_order->get_order()->get_customer_id() <= 0 ) { + $key = $shipment_order->get_order_return_request_key(); + + if ( ! empty( $key ) ) { + $url = add_query_arg( array( 'key' => $key ), $url ); + } else { + $url = ''; + } + } + + /** + * Filter to adjust the URL the customer (or guest) might access to add a return to a certain order. + * + * @param string $url The URL pointing to the add return page. + * @param Order $order The order object. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipments_add_return_shipment_url', $url, $shipment_order->get_order() ); +} + +/** + * @param WC_Order $order + * + * @return mixed + */ +function wc_gzd_order_is_customer_returnable( $order, $check_date = true ) { + $is_returnable = false; + + if ( ! $shipment_order = wc_gzd_get_shipment_order( $order ) ) { + return false; + } + + if ( $provider = wc_gzd_get_order_shipping_provider( $order ) ) { + $is_returnable = $provider->supports_customer_returns( $shipment_order->get_order() ); + + if ( $shipment_order->get_order()->get_customer_id() <= 0 && ! $provider->supports_guest_returns() ) { + $is_returnable = false; + } + } + + // Shipment is fully returned + if ( ! $shipment_order->needs_return() ) { + $is_returnable = false; + } + + // Check days left for return + $maximum_days = Package::get_setting( 'customer_return_open_days' ); + + if ( $check_date && ! empty( $maximum_days ) ) { + $maximum_days = absint( $maximum_days ); + + if ( ! empty( $maximum_days ) ) { + + $completed_date = $shipment_order->get_order()->get_date_created(); + + if ( $shipment_order->get_date_shipped() ) { + $completed_date = $shipment_order->get_date_shipped(); + } elseif ( $shipment_order->get_order()->get_date_completed() ) { + $completed_date = $shipment_order->get_order()->get_date_completed(); + } + + /** + * Filter to adjust the completed date of an order used to determine whether an order is + * still returnable by the customer or not. The date is constructed by checking for existence in the following order: + * + * 1. The date the order was shipped completely + * 2. The date the order was marked as completed + * 3. The date the order was created + * + * @param WC_DateTime $completed_date The order completed date. + * @param WC_Order $order The order instance. + * + * @since 3.1.0 + * @package Vendidero/Germanized/Shipments + */ + $completed_date = apply_filters( 'woocommerce_gzd_order_return_completed_date', $completed_date, $shipment_order->get_order() ); + + if ( $completed_date ) { + $today = new WC_DateTime(); + $diff = $today->diff( $completed_date ); + + if ( $diff->days > $maximum_days ) { + $is_returnable = false; + } + } + } + } + + /** + * Filter to decide whether a customer might add return request to a certain order. + * + * @param bool $is_returnable Whether or not shipment supports customer added returns + * @param WC_Order $order The order instance for which the return shall be created. + * @param bool $check_date Whether to check for a maximum date or not. + * + * @since 3.1.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_order_is_returnable_by_customer', $is_returnable, $shipment_order->get_order(), $check_date ); +} + +/** + * @param $order + * + * @return bool|\Vendidero\Germanized\Shipments\Interfaces\ShippingProvider + */ +function wc_gzd_get_order_shipping_provider( $order ) { + if ( is_numeric( $order ) ) { + $order = wc_get_order( $order ); + } + + if ( ! $order ) { + return false; + } + + $provider = false; + + if ( $method = wc_gzd_get_shipping_provider_method( wc_gzd_get_shipment_order_shipping_method_id( $order ) ) ) { + $provider = $method->get_provider_instance(); + } + + /** + * Filters the shipping provider detected for a specific order. + * + * @param bool|\Vendidero\Germanized\Shipments\Interfaces\ShippingProvider $provider The shipping provider instance. + * @param WC_Order $order The order instance. + * + * @since 3.1.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_get_order_shipping_provider', $provider, $order ); +} + +function wc_gzd_get_customer_order_return_request_key() { + $key = ( isset( $_REQUEST['key'] ) ? wc_clean( wp_unslash( $_REQUEST['key'] ) ) : '' ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended + + return $key; +} + +function wc_gzd_customer_can_add_return_shipment( $order_id ) { + $can_view_shipments = false; + + if ( isset( $_REQUEST['key'] ) && ! empty( $_REQUEST['key'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $key = wc_gzd_get_customer_order_return_request_key(); + + if ( ( $order_shipment = wc_gzd_get_shipment_order( $order_id ) ) && ! empty( $key ) ) { + + if ( hash_equals( $order_shipment->get_order_return_request_key(), $key ) ) { + $can_view_shipments = true; + } + } + } elseif ( is_user_logged_in() ) { + $can_view_shipments = current_user_can( 'view_order', $order_id ); + } + + /** + * Filters whether a logged in user (or guest) might view shipments belonging to an order or not. + * + * @param bool $can_view_shipments Whether the user (or guest) might see shipments or not. + * @param integer $order_id The order id. + * + * @since 3.1.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_customer_can_view_shipments', $can_view_shipments, $order_id ); +} + +/** + * @param WC_Order|integer $order + */ +function wc_gzd_customer_return_needs_manual_confirmation( $order ) { + if ( is_numeric( $order ) ) { + $order = wc_get_order( $order ); + } + + if ( ! $order ) { + return true; + } + + $needs_manual_confirmation = true; + + if ( $provider = wc_gzd_get_order_shipping_provider( $order ) ) { + $needs_manual_confirmation = $provider->needs_manual_confirmation_for_returns(); + } + + /** + * Filter to decide whether a customer added return of a certain order + * needs manual confirmation by the shop manager or not. + * + * @param bool $needs_manual_confirmation Whether needs manual confirmation or not. + * @param WC_Order $order The order instance for which the return shall be created. + * + * @since 3.1.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_customer_return_needs_manual_confirmation', $needs_manual_confirmation, $order ); +} + +/** + * Get account shipments actions. + * + * @since 3.2.0 + * @param int|Shipment $shipment Shipment instance or ID. + * @return array + */ +function wc_gzd_get_account_shipments_actions( $shipment ) { + + if ( ! is_object( $shipment ) ) { + $shipment_id = absint( $shipment ); + $shipment = wc_gzd_get_shipment( $shipment_id ); + } + + if ( ! $shipment ) { + return array(); + } + + $actions = array( + 'view' => array( + 'url' => $shipment->get_view_shipment_url(), + 'name' => _x( 'View', 'shipments', 'woocommerce-germanized' ), + ), + ); + + if ( 'return' === $shipment->get_type() && $shipment->has_label() && ! $shipment->has_status( 'delivered' ) ) { + $actions['download-label'] = array( + 'url' => $shipment->get_label()->get_download_url(), + 'name' => _x( 'Download label', 'shipments', 'woocommerce-germanized' ), + ); + } + + /** + * Filter to adjust available actions in the shipments table view on the customer account page + * for a specific shipment. + * + * @param string[] $actions Available actions containing an id as key and a URL and name. + * @param Shipment $shipment The shipment instance. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_account_shipments_actions', $actions, $shipment ); +} + +function wc_gzd_shipments_get_product( $the_product ) { + try { + if ( is_a( $the_product, '\Vendidero\Germanized\Shipments\Product' ) ) { + return $the_product; + } + + return new \Vendidero\Germanized\Shipments\Product( $the_product ); + } catch ( \Exception $e ) { + return false; + } +} + +function wc_gzd_get_volume_dimension( $dimension, $to_unit, $from_unit = '' ) { + $to_unit = strtolower( $to_unit ); + + if ( empty( $from_unit ) ) { + $from_unit = strtolower( get_option( 'woocommerce_dimension_unit' ) ); + } + + // Unify all units to cm first. + if ( $from_unit !== $to_unit ) { + switch ( $from_unit ) { + case 'm': + $dimension *= 1000000; + break; + case 'mm': + $dimension *= 0.001; + break; + } + + // Output desired unit. + switch ( $to_unit ) { + case 'm': + $dimension *= 0.000001; + break; + case 'mm': + $dimension *= 1000; + break; + } + } + + return ( $dimension < 0 ) ? 0 : $dimension; +} diff --git a/packages/woocommerce-germanized-shipments/includes/wc-gzd-shipment-template-hooks.php b/packages/woocommerce-germanized-shipments/includes/wc-gzd-shipment-template-hooks.php new file mode 100644 index 000000000..3f211f474 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/includes/wc-gzd-shipment-template-hooks.php @@ -0,0 +1,28 @@ + false, + 'show_image' => false, + 'image_size' => array( 32, 32 ), + 'plain_text' => false, + 'sent_to_admin' => false, + ); + + $args = wp_parse_args( $args, $defaults ); + $template = $args['plain_text'] ? 'emails/plain/email-shipment-items.php' : 'emails/email-shipment-items.php'; + + wc_get_template( + $template, + /** + * Filter to adjust the arguments passed to retrieving ShipmentItems for display in an Email. + * + * @param array $args Array containing the arguments passed. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + apply_filters( + 'woocommerce_gzd_email_shipment_items_args', + array( + 'shipment' => $shipment, + 'items' => $shipment->get_items(), + 'show_sku' => $args['show_sku'], + 'show_image' => $args['show_image'], + 'image_size' => $args['image_size'], + 'plain_text' => $args['plain_text'], + 'sent_to_admin' => $args['sent_to_admin'], + ) + ) + ); + + /** + * Filter that allows adjusting the HTML output of the shipment email item table. + * + * @param string $html The HTML output. + * @param Shipment $shipment The shipment instance. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_email_shipment_items_table', ob_get_clean(), $shipment ); + } +} + +if ( ! function_exists( 'woocommerce_gzd_shipments_template_view_shipments' ) ) { + + function woocommerce_gzd_shipments_template_view_shipments( $order_id ) { + + if ( ( ! ( $order = wc_get_order( $order_id ) ) ) || ( ! current_user_can( 'view_order', $order_id ) ) ) { + echo '
' . esc_html_x( 'Invalid order.', 'shipments', 'woocommerce-germanized' ) . ' ' . esc_html_x( 'My account', 'shipments', 'woocommerce-germanized' ) . '
'; + + return; + } + + $shipments = wc_gzd_get_shipments( + array( + 'order_id' => $order_id, + 'type' => 'simple', + 'status' => wc_gzd_get_shipment_customer_visible_statuses(), + ) + ); + + $returns = wc_gzd_get_shipments( + array( + 'order_id' => $order_id, + 'type' => 'return', + 'status' => wc_gzd_get_shipment_customer_visible_statuses( 'return' ), + ) + ); + + wc_get_template( + 'myaccount/order-shipments.php', + array( + 'order_id' => $order_id, + 'order' => $order, + 'shipments' => $shipments, + 'returns' => $returns, + ) + ); + } +} + +if ( ! function_exists( 'woocommerce_gzd_shipments_template_view_shipment' ) ) { + + function woocommerce_gzd_shipments_template_view_shipment( $shipment_id ) { + + if ( ( ! ( $shipment = wc_gzd_get_shipment( $shipment_id ) ) ) || ( ! current_user_can( 'view_order', $shipment->get_order_id() ) ) ) { + echo '
' . esc_html_x( 'Invalid shipment.', 'shipments', 'woocommerce-germanized' ) . ' ' . esc_html_x( 'My account', 'shipments', 'woocommerce-germanized' ) . '
'; + + return; + } + + wc_get_template( + 'myaccount/view-shipment.php', + array( + 'shipment' => $shipment, + 'shipment_id' => $shipment_id, + ) + ); + } +} + +if ( ! function_exists( 'woocommerce_gzd_shipments_template_add_return_shipment' ) ) { + + function woocommerce_gzd_shipments_template_add_return_shipment( $order_id ) { + + if ( ( ! ( $order = wc_get_order( $order_id ) ) ) || ( ! wc_gzd_customer_can_add_return_shipment( $order_id ) ) ) { + echo '
' . esc_html_x( 'Invalid order.', 'shipments', 'woocommerce-germanized' ) . ' ' . esc_html_x( 'My account', 'shipments', 'woocommerce-germanized' ) . '
'; + return; + } + + if ( ! wc_gzd_order_is_customer_returnable( $order_id ) ) { + echo '
' . esc_html_x( 'Currently you cannot add new return requests to that order. If you have questions regarding the return of that order please contact us for further information.', 'shipments', 'woocommerce-germanized' ) . ( is_user_logged_in() ? ' ' . esc_html_x( 'View order', 'shipments', 'woocommerce-germanized' ) . '' : '' ) . '
'; + return; + } + + $notices = function_exists( 'wc_print_notices' ) ? wc_print_notices( true ) : ''; + + // Output notices in case notices have not been outputted yet. + if ( ! empty( $notices ) ) { + echo '
' . $notices . '
'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + } + + wc_get_template( + 'myaccount/add-return-shipment.php', + array( + 'order' => $order, + 'order_id' => $order_id, + 'shipment_order' => wc_gzd_get_shipment_order( $order ), + ) + ); + } +} + +if ( ! function_exists( 'woocommerce_gzd_shipment_details_table' ) ) { + + function woocommerce_gzd_shipment_details_table( $shipment_id ) { + if ( ! $shipment_id ) { + return; + } + + wc_get_template( + 'shipment/shipment-details.php', + array( + 'shipment_id' => $shipment_id, + ) + ); + } +} + +if ( ! function_exists( 'woocommerce_gzd_return_shipments_template_instructions' ) ) { + + function woocommerce_gzd_return_shipments_template_instructions( $shipment_id ) { + if ( $shipment = wc_gzd_get_shipment( $shipment_id ) ) { + + if ( 'return' !== $shipment->get_type() ) { + return; + } + + if ( ! $shipment->has_status( array( 'processing', 'sent' ) ) ) { + return; + } + + wc_get_template( + 'shipment/shipment-return-instructions.php', + array( + 'shipment' => $shipment, + 'shipment_id' => $shipment_id, + ) + ); + } + } +} diff --git a/packages/woocommerce-germanized-shipments/license.txt b/packages/woocommerce-germanized-shipments/license.txt new file mode 100644 index 000000000..16aa3cb39 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/license.txt @@ -0,0 +1,699 @@ +WooCommerce Germanized Shipments + +Copyright 2019 by the contributors + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +This program incorporates work covered by the following copyright and +permission notices: + + WooCommerce + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright © 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright © + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright © + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file diff --git a/packages/woocommerce-germanized-shipments/src/AddressSplitter.php b/packages/woocommerce-germanized-shipments/src/AddressSplitter.php new file mode 100644 index 000000000..2b59c5e0e --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/AddressSplitter.php @@ -0,0 +1,272 @@ + + * + */ + $addition_2_introducers = '(?: + # {{{ Additions relating to who (a natural person) is addressed + \s+ [Cc] \s* \/ \s* [Oo] \s + | ℅ + | \s+ care \s+ of \s+ + # German, Swiss, Austrian + | \s+ (?: p|p.\s*|per\s+ ) (?: A|A.|Adr.|(?<=\s)Adresse ) \s + | \s+ p. \s* A. \s + | \s+ (?: z | z.\s* | zu\s+ ) (?: Hd|Hd.|(?<=\s)Händen|(?<=\s)Haenden|(?<=\s)Handen) \s+ + ## o. V. i. A. = oder Vertreter im Amt + | \s+ (?: o | o.\s* | oder\s+ ) + (?: V | V.\s* | (?<=\s)Vertreter\s+ ) + (?: i | i.\s* | (?<=\s)im\s+ ) + (?: A | A.\s* | (?<=\s)Amt\s+ ) + # }}} + # {{{ Additions which further specify more precisely the location + | \s+ (?: Haus ) \s + | \s+ (?: WG | W\.G\. | WG\. | Wohngemeinschaft ) ($ | \s) + | \s+ (?: [Aa]partment | APT \.? | Apt \.? ) \s + | \s+ (?: [Ff]lat ) \s + | (?: # Numeric-based location specifiers (e.g., "3. Stock"): + \s+ + (?: + [\p{N}]+ # A number, … + (?i: st | nd | rd | th)? # …, optionally followed by an English number suffix + \.? # …, followed by an optional dot, + \s* # …, followed by optional spacing + )? + (?: # Specifying category: + (?i: Stock | Stockwerk) + | App \.? | Apt \.? | (?i: Appartment | Apartment) + ) + # At the end of the string or followed by a space + (?: $ | \s) + ) + | (?: + \s+ (?: + # English language stop words wrt location from source [1] + # (extracted only those which may not be _exclusively_ part of + # street names): + | ANX \.? | (?i: ANNEX) + | APT \.? | (?i: APARTMENT) + | ARC \.? | (?i: ARCADE) + | AVE \.? | (?i: AVENUE) + | BSMT \.? | (?i: BASEMENT) + | BLDG \.? | (?i: BUILDING) + | CP \.? | (?i: CAMP) + | COR \.? | (?i: CORNER) + | CORS \.? | (?i: CORNERS) + | CT \.? | (?i: COURT) + | CTS \.? | (?i: COURTS) + | DEPT \.? | (?i: DEPARTMENT) + | DV \.? | (?i: DIVIDE) + | EST \.? | (?i: ESTATE) + | EXT \.? | (?i: EXTENSION) + | FRY \.? | (?i: FERRY) + | FLD \.? | (?i: FIELD) + | FLDS \.? | (?i: FIELDS) + | FLT \.? | (?i: FLAT) + | FL \.? | (?i: FLOOR) + | FRNT \.? | (?i: FRONT) + | GDNS \.? | (?i: GARDEN) + | GDNS \.? | (?i: GARDENS) + | GTWY \.? | (?i: GATEWAY) + | GRN \.? | (?i: GREEN) + | GRV \.? | (?i: GROVE) + | HNGR \.? | (?i: HANGER) + | HBR \.? | (?i: HARBOR) + | HVN \.? | (?i: HAVEN) + | KY \.? | (?i: KEY) + | LBBY \.? | (?i: LOBBY) + | LCKS \.? | (?i: LOCK) + | LCKS \.? | (?i: LOCKS) + | LDG \.? | (?i: LODGE) + | MNR \.? | (?i: MANOR) + | OFC \.? | (?i: OFFICE) + | PKWY \.? | (?i: PARKWAY) + | PH \.? | (?i: PENTHOUSE) + | PRT \.? | (?i: PORT) + | RADL \.? | (?i: RADIAL) + | RM \.? | (?i: ROOM) + | SPC \.? | (?i: SPACE) + | SQ \.? | (?i: SQUARE) + | STA \.? | (?i: STATION) + | STE \.? | (?i: SUITE) + | TER \.? | (?i: TERRACE) + | TRAK \.? | (?i: TRACK) + | TRL \.? | (?i: TRAIL) + | TRLR \.? | (?i: TRAILER) + | TUNL \.? | (?i: TUNNEL) + | VW \.? | (?i: VIEW) + | VIS \.? | (?i: VISTA) + # Custom custom additions: + | (?i: Story | Storey) + | LVL \.? | (?i: Level) + ) + # May optionally be followed directly by a number+letter + # combination (e.g., "LVL3C"): + (?: [\p{N}]+[\p{L}]* )? + # Occurs at the end of the string or followed by a space: + ($ | \s) + ) + # Heuristic to match location specifiers. These must not be + # conflated with house number extensions as in "12 AB". Hence + # our heuristic is at least 3 letters with the first letter being + # spelled as a capital. E.g., it would match "Haus", "Gebäude" or + # "Arbeitspl.", but not "AAB". + | \s+ ( [\p{Lu}\p{Lt}] [\p{Ll}\p{Lo}]{2,} \.? ) ($ | \s) + # }}} + )'; + $regex = ' + /\A\s* + (?: ######################################################################### + # Option A: [] # + # [] # + ######################################################################### + (?:(?P.*?),\s*)? # Addition to address 1 + (?:No\.\s*)? + (?P + (?P + \pN+(\s+\d+\/\d+)? + ) + (?: + \s*[\-\/\.]?\s* + (?P(?:[a-zA-Z\pN]){1,2}) + \s+ + )? + ) + \s*,?\s* + (?P(?:[a-zA-Z]\s*|\pN\pL{2,}\s\pL)\S[^,#]*?(?(?!\s).*?))? # Addition to address 2 + | ######################################################################### + # Option B: [] # + # [] # + ######################################################################### + (?:(?P.*?),\s*(?=.*[,\/]))? # Addition to address 1 + (?!\s*No\.)(?P[^0-9# ]\s*\S(?:[^,#](?!\b\pN+\s))*?(? + (?P + \pN+ + ) + (?: + # Match house numbers that are (optionally) amended + # by a dash (e.g., 12-13) or slash (e.g., 12\/A): + (?: \s*[\-\/]\s* )* + (?P + (?: + # Do not match "care-of"-like additions as + # house numbers: + (?!' . $addition_2_introducers . ') + \s*[\pL\pN]+ + ) + # Match any further slash- or dash-based house + # number extensions: + (?: + # Do not match "care-of"-like additions as + # house numbers: + (?!' . $addition_2_introducers . ') + # Match any (optionally space-separated) + # additionals parts of house numbers after + # slashes or dashes. + \s* [\-\/] \s* + [\pL\pN]+ + )* + ) + )? + ) # House number + (?: + (?:\s*[-,\/]|(?=\#)|\s)\s*(?!\s*No\.)\s* + (?P(?!\s).*?) + )? + ) + \s*\Z/xu'; + $result = preg_match( $regex, $address, $matches ); + if ( 0 === $result ) { + throw new Exception( sprintf( 'Error occurred while trying to split address \'%s\'', $address ) ); + } elseif ( false === $result ) { + throw new RuntimeException( sprintf( 'Error occurred while trying to split address \'%s\'', $address ) ); + } + if ( ! empty( $matches['A_Street_name'] ) ) { + return array( + 'additionToAddress1' => $matches['A_Addition_to_address_1'], + 'streetName' => $matches['A_Street_name'], + 'houseNumber' => $matches['A_House_number_match'], + 'houseNumberParts' => array( + 'base' => $matches['A_House_number_base'], + 'extension' => isset( $matches['A_House_number_extension'] ) ? trim( $matches['A_House_number_extension'] ) : '', + ), + 'additionToAddress2' => ( isset( $matches['A_Addition_to_address_2'] ) ) ? $matches['A_Addition_to_address_2'] : '', + ); + } else { + return array( + 'additionToAddress1' => $matches['B_Addition_to_address_1'], + 'streetName' => $matches['B_Street_name'], + 'houseNumber' => $matches['B_House_number_match'], + 'houseNumberParts' => array( + 'base' => $matches['B_House_number_base'], + 'extension' => isset( $matches['B_House_number_extension'] ) ? trim( $matches['B_House_number_extension'] ) : '', + ), + 'additionToAddress2' => isset( $matches['B_Addition_to_address_2'] ) ? $matches['B_Addition_to_address_2'] : '', + ); + } + } + + /** + * @param string $house_number A house number string to split in base and extension + * + * @return array + * @throws Exception + */ + public static function split_house_number( $house_number ) { + $regex = + '/ + \A\s* # Trim white spaces at the beginning + (?:[nN][oO][\.:]?\s*)? # Trim sth. like No. + (?:\#\s*)? # Trim # + (? + [\pN]+ # House Number base (only the number) + ) + \s*[\/\-\.]?\s* # Separator (optional) + (? # House number extension (optional) + .*? # Here we allow every character. Everything after the separator is interpreted as extension + ) + \s*\Z # Trim white spaces at the end + /xu'; // Option (u)nicode and e(x)tended syntax + $result = preg_match( $regex, $house_number, $matches ); + if ( 0 === $result ) { + throw new Exception( sprintf( 'Error occurred while trying to house number \'%s\'', $house_number ) ); + } elseif ( false === $result ) { + throw new RuntimeException( sprintf( 'Error occurred while trying to house number \'%s\'', $house_number ) ); + } + + return array( + 'base' => $matches['House_number_base'], + 'extension' => $matches['House_number_extension'], + ); + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Admin/Admin.php b/packages/woocommerce-germanized-shipments/src/Admin/Admin.php new file mode 100644 index 000000000..94cc88c52 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Admin/Admin.php @@ -0,0 +1,1138 @@ +get_id() !== $post_id ) { + $the_order = wc_get_order( $post_id ); + } + + if ( $shipment_order = wc_gzd_get_shipment_order( $the_order ) ) { + $shipping_status = $shipment_order->get_shipping_status(); + $status_html = '' . esc_html( wc_gzd_get_shipment_order_shipping_status_name( $shipping_status ) ) . ''; + + if ( in_array( $shipping_status, array( 'shipped', 'partially-shipped' ), true ) && $shipment_order->get_shipments() ) { + echo '' . wp_kses_post( $status_html ) . ''; + } else { + echo wp_kses_post( $status_html ); + } + } + } + } + + public static function register_order_shipping_status_column( $columns ) { + $new_columns = array(); + $added_column = false; + + foreach ( $columns as $column_name => $title ) { + if ( ! $added_column && ( 'shipping_address' === $column_name || 'wc_actions' === $column_name ) ) { + $new_columns['shipping_status'] = _x( 'Shipping Status', 'shipments-order-column-name', 'woocommerce-germanized' ); + $added_column = true; + } + + $new_columns[ $column_name ] = $title; + } + + if ( ! $added_column ) { + $new_columns['shipping_status'] = _x( 'Shipping Status', 'shipments-order-column-name', 'woocommerce-germanized' ); + } + + return $new_columns; + } + + /** + * In case the shipper/return country is set to AF (or DE with missing state) due to a bug in Woo, make sure + * to automatically adjust it to the right value in case the base country option is being saved. + * + * @return void + */ + public static function observe_base_country_setting() { + if ( isset( $_POST['woocommerce_default_country'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing + $new_base_country = wc_format_country_state_string( get_option( 'woocommerce_default_country' ) ); + + if ( 'AF' !== $new_base_country['country'] ) { + $shipper_country = wc_format_country_state_string( get_option( 'woocommerce_gzd_shipments_shipper_address_country' ) ); + $return_country = wc_format_country_state_string( get_option( 'woocommerce_gzd_shipments_return_address_country' ) ); + + if ( 'AF' === $shipper_country['country'] || ( 'DE' === $new_base_country['country'] && 'DE' === $shipper_country['country'] && empty( $shipper_country['state'] ) && ! empty( $new_base_country['state'] ) ) ) { + update_option( 'woocommerce_gzd_shipments_shipper_address_country', get_option( 'woocommerce_default_country' ) ); + } + + if ( 'AF' === $return_country['country'] || ( 'DE' === $new_base_country['country'] && 'DE' === $return_country['country'] && empty( $return_country['state'] ) && ! empty( $return_country['state'] ) ) ) { + update_option( 'woocommerce_gzd_shipments_return_address_country', get_option( 'woocommerce_default_country' ) ); + } + } + } + } + + public static function product_options() { + global $post, $thepostid, $product_object; + + $_product = wc_get_product( $product_object ); + $shipments_product = wc_gzd_shipments_get_product( $_product ); + + $countries = WC()->countries->get_countries(); + $countries = array_merge( array( '0' => _x( 'Select a country', 'shipments', 'woocommerce-germanized' ) ), $countries ); + + woocommerce_wp_text_input( + array( + 'id' => '_hs_code', + 'label' => _x( 'HS-Code (Customs)', 'shipments', 'woocommerce-germanized' ), + 'desc_tip' => true, + 'description' => _x( 'The HS Code is a number assigned to every possible commodity that can be imported or exported from any country.', 'shipments', 'woocommerce-germanized' ), + 'value' => $shipments_product->get_hs_code( 'edit' ), + ) + ); + + woocommerce_wp_select( + array( + 'options' => $countries, + 'id' => '_manufacture_country', + 'label' => _x( 'Country of manufacture (Customs)', 'shipments', 'woocommerce-germanized' ), + 'desc_tip' => true, + 'description' => _x( 'The country of manufacture is needed for customs of international shipping.', 'shipments', 'woocommerce-germanized' ), + 'value' => $shipments_product->get_manufacture_country( 'edit' ), + ) + ); + + do_action( 'woocommerce_gzd_shipments_product_options', $shipments_product ); + } + + /** + * @param \WC_Product $product + */ + public static function save_product( $product ) { + $hs_code = isset( $_POST['_hs_code'] ) ? wc_clean( wp_unslash( $_POST['_hs_code'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing + $country = isset( $_POST['_manufacture_country'] ) ? wc_clean( wp_unslash( $_POST['_manufacture_country'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing + + $shipments_product = wc_gzd_shipments_get_product( $product ); + $shipments_product->set_hs_code( $hs_code ); + $shipments_product->set_manufacture_country( $country ); + + /** + * Remove legacy data upon saving in case it is not transmitted (e.g. DHL standalone plugin). + */ + if ( apply_filters( 'woocommerce_gzd_shipments_remove_legacy_customs_meta', isset( $_POST['_dhl_hs_code'] ) ? false : true, $product ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing + $product->delete_meta_data( '_dhl_hs_code' ); + $product->delete_meta_data( '_dhl_manufacture_country' ); + } + + do_action( 'woocommerce_gzd_shipments_save_product_options', $shipments_product ); + } + + public static function check_upload_dir() { + $dir = Package::get_upload_dir(); + $path = $dir['basedir']; + $dirname = basename( $path ); + + if ( @is_dir( $dir['basedir'] ) ) { // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged + return; + } + ?> +
+

wp-content/uploads/' . esc_html( $dirname ) . '' ); ?>

+
+ $value ) { + if ( isset( $value['id'] ) && $value['id'] === $id ) { + if ( ! empty( $type ) && $type !== $value['type'] ) { + continue; + } + return $key; + } + } + } + + return false; + } + + protected static function add_settings_after( $settings, $id, $insert = array(), $type = '' ) { + $key = self::get_setting_key_by_id( $settings, $id, $type ); + + if ( is_numeric( $key ) ) { + $key ++; + $settings = array_merge( array_merge( array_slice( $settings, 0, $key, true ), $insert ), array_slice( $settings, $key, count( $settings ) - 1, true ) ); + } else { + $settings += $insert; + } + + return $settings; + } + + public static function register_endpoint_settings( $settings, $current_section ) { + if ( '' === $current_section ) { + $endpoints = array( + array( + 'title' => _x( 'View Shipments', 'shipments', 'woocommerce-germanized' ), + 'desc' => _x( 'Endpoint for the "My account → View shipments" page.', 'shipments', 'woocommerce-germanized' ), + 'id' => 'woocommerce_gzd_shipments_view_shipments_endpoint', + 'type' => 'text', + 'default' => 'view-shipments', + 'desc_tip' => true, + ), + array( + 'title' => _x( 'View shipment', 'shipments', 'woocommerce-germanized' ), + 'desc' => _x( 'Endpoint for the "My account → View shipment" page.', 'shipments', 'woocommerce-germanized' ), + 'id' => 'woocommerce_gzd_shipments_view_shipment_endpoint', + 'type' => 'text', + 'default' => 'view-shipment', + 'desc_tip' => true, + ), + array( + 'title' => _x( 'Add Return Shipment', 'shipments', 'woocommerce-germanized' ), + 'desc' => _x( 'Endpoint for the "My account → Add return shipment" page.', 'shipments', 'woocommerce-germanized' ), + 'id' => 'woocommerce_gzd_shipments_add_return_shipment_endpoint', + 'type' => 'text', + 'default' => 'add-return-shipment', + 'desc_tip' => true, + ), + ); + + $settings = self::add_settings_after( $settings, 'woocommerce_myaccount_downloads_endpoint', $endpoints ); + } + + return $settings; + } + + public static function menu_return_count() { + global $submenu; + + if ( isset( $submenu['woocommerce'] ) ) { + + /** + * Filter to adjust whether to include requested return count in admin menu or not. + * + * @param boolean $show_count Whether to show count or not. + * + * @since 3.1.3 + * @package Vendidero/Germanized/Shipments + */ + if ( apply_filters( 'woocommerce_gzd_shipments_include_requested_return_count_in_menu', true ) && current_user_can( 'manage_woocommerce' ) ) { + $return_count = wc_gzd_get_shipment_count( 'requested', 'return' ); + + if ( $return_count ) { + foreach ( $submenu['woocommerce'] as $key => $menu_item ) { + if ( 0 === strpos( $menu_item[0], _x( 'Returns', 'shipments', 'woocommerce-germanized' ) ) ) { + $submenu['woocommerce'][ $key ][0] .= ' ' . number_format_i18n( $return_count ) . ''; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited + break; + } + } + } + } + } + } + + public static function get_admin_shipment_item_columns( $shipment ) { + $item_columns = array( + 'name' => array( + 'title' => _x( 'Item', 'shipments', 'woocommerce-germanized' ), + 'size' => 6, + 'order' => 5, + ), + 'quantity' => array( + 'title' => _x( 'Quantity', 'shipments', 'woocommerce-germanized' ), + 'size' => 3, + 'order' => 10, + ), + 'action' => array( + 'title' => _x( 'Actions', 'shipments', 'woocommerce-germanized' ), + 'size' => 3, + 'order' => 15, + ), + ); + + if ( 'return' === $shipment->get_type() ) { + $item_columns['return_reason'] = array( + 'title' => _x( 'Reason', 'shipments', 'woocommerce-germanized' ), + 'size' => 3, + 'order' => 7, + ); + + $item_columns['name']['size'] = 5; + $item_columns['quantity']['size'] = 2; + $item_columns['action']['size'] = 2; + } + + uasort( $item_columns, array( __CLASS__, 'sort_shipment_item_columns' ) ); + + /** + * Filter to adjust shipment item columns shown in admin view. + * + * @param array $item_columns The columns available. + * @param Shipment $shipment The shipment. + * + * @since 3.1.0 + * @package Vendidero/Germanized/Shipments + */ + return apply_filters( 'woocommerce_gzd_shipments_meta_box_shipment_item_columns', $item_columns, $shipment ); + } + + protected static function sort_shipment_item_columns( $a, $b ) { + if ( $a['order'] === $b['order'] ) { + return 0; + } + + return ( $a['order'] < $b['order'] ) ? -1 : 1; + } + + public static function save_packaging_list() { + $current_key_list = array(); + $packaging_ids_after_save = array(); + + foreach ( wc_gzd_get_packaging_list() as $pack ) { + $current_key_list[] = $pack->get_id(); + } + + if ( isset( $_POST['packaging'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing + $packaging_post = wc_clean( wp_unslash( $_POST['packaging'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing + $order = 0; + $available_types = array_keys( wc_gzd_get_packaging_types() ); + + foreach ( $packaging_post as $packaging ) { + $packaging = wc_clean( $packaging ); + $packaging_id = isset( $packaging['packaging_id'] ) ? absint( $packaging['packaging_id'] ) : 0; + $packaging_obj = wc_gzd_get_packaging( $packaging_id ); + + if ( $packaging_obj ) { + $packaging_obj->set_props( + array( + 'type' => ! in_array( $packaging['type'], $available_types, true ) ? 'cardboard' : $packaging['type'], + 'weight' => empty( $packaging['weight'] ) ? 0 : $packaging['weight'], + 'description' => empty( $packaging['description'] ) ? '' : $packaging['description'], + 'length' => empty( $packaging['length'] ) ? 0 : $packaging['length'], + 'width' => empty( $packaging['width'] ) ? 0 : $packaging['width'], + 'height' => empty( $packaging['height'] ) ? 0 : $packaging['height'], + 'max_content_weight' => empty( $packaging['max_content_weight'] ) ? 0 : $packaging['max_content_weight'], + 'order' => ++$order, + ) + ); + + if ( empty( $packaging_obj->get_description() ) ) { + if ( $packaging_obj->get_id() > 0 ) { + $packaging_obj->delete( true ); + continue; + } else { + continue; + } + } + + $packaging_obj->save(); + $packaging_ids_after_save[] = $packaging_obj->get_id(); + } + } + } + + $to_delete = array_diff( $current_key_list, $packaging_ids_after_save ); + + if ( ! empty( $to_delete ) ) { + foreach ( $to_delete as $delete_id ) { + if ( $packaging = wc_gzd_get_packaging( $delete_id ) ) { + $packaging->delete( true ); + } + } + } + } + + public static function save_return_reasons( $tab, $current_section ) { + if ( '' !== $current_section ) { + return; + } + + $reasons = array(); + + if ( isset( $_POST['shipment_return_reason'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing + $reasons_post = wc_clean( wp_unslash( $_POST['shipment_return_reason'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing + $order = 0; + + foreach ( $reasons_post as $reason ) { + $code = isset( $reason['code'] ) ? $reason['code'] : ''; + $reason_text = isset( $reason['reason'] ) ? $reason['reason'] : ''; + + if ( empty( $code ) ) { + $code = sanitize_title( $reason_text ); + } + + if ( ! empty( $reason_text ) ) { + $reasons[] = array( + 'order' => ++$order, + 'code' => $code, + 'reason' => $reason_text, + ); + } + } + } + // phpcs:enable + + update_option( 'woocommerce_gzd_shipments_return_reasons', $reasons ); + } + + public static function output_return_reasons_field( $value ) { + ob_start(); + ?> + + + +
+ + + + + + + + + + + + + + '; + } + ?> + + + + + + +
 
+
+ + + + + + + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + +
get_title() ); ?> get_status() ) ); ?> + get_date_start()->date_i18n( wc_date_format() ); + + printf( + '', + esc_attr( $report->get_date_start()->date( 'c' ) ), + esc_html( $report->get_date_start()->date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) ) ), + esc_html( $show_date ) + ); + ?> + + get_date_end()->date_i18n( wc_date_format() ); + + printf( + '', + esc_attr( $report->get_date_end()->date( 'c' ) ), + esc_html( $report->get_date_end()->date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) ) ), + esc_html( $show_date ) + ); + ?> + + get_total_weight(), wc_gzd_get_packaging_weight_unit() ) ); ?> + + get_total_count() ); ?> +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
+ + + + + + + + + + + + + + +
+
+ + + + 'shop_order', + 'bulk_action' => $report_action, + 'changed' => $changed, + 'ids' => join( ',', $ids ), + ), + $redirect_to + ); + + return esc_url_raw( $redirect_to ); + } else { + return $redirect_to; + } + } + + public static function define_order_bulk_actions( $actions ) { + $actions['gzd_create_shipments'] = _x( 'Create shipments', 'shipments', 'woocommerce-germanized' ); + + return $actions; + } + + public static function set_screen_option( $new_value, $option, $value ) { + + if ( in_array( $option, array( 'woocommerce_page_wc_gzd_shipments_per_page', 'woocommerce_page_wc_gzd_return_shipments_per_page' ), true ) ) { + return absint( $value ); + } + + return $new_value; + } + + public static function shipments_menu() { + add_submenu_page( 'woocommerce', _x( 'Shipments', 'shipments', 'woocommerce-germanized' ), _x( 'Shipments', 'shipments', 'woocommerce-germanized' ), 'manage_woocommerce', 'wc-gzd-shipments', array( __CLASS__, 'shipments_page' ) ); + add_submenu_page( 'woocommerce', _x( 'Returns', 'shipments', 'woocommerce-germanized' ), _x( 'Returns', 'shipments', 'woocommerce-germanized' ), 'manage_woocommerce', 'wc-gzd-return-shipments', array( __CLASS__, 'returns_page' ) ); + } + + /** + * @param Shipment $shipment + */ + public static function get_shipment_tracking_html( $shipment ) { + $tracking_html = ''; + + if ( $tracking_id = $shipment->get_tracking_id() ) { + + if ( $tracking_url = $shipment->get_tracking_url() ) { + $tracking_html = '' . $tracking_id . ''; + } else { + $tracking_html = '' . $tracking_id . ''; + } + } + + return $tracking_html; + } + + /** + * @param Table $table + */ + protected static function setup_table( $table ) { + global $wp_list_table; + + $wp_list_table = $table; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited + $doaction = $wp_list_table->current_action(); + + if ( $doaction ) { + check_admin_referer( 'bulk-shipments' ); + + $pagenum = $wp_list_table->get_pagenum(); + $parent_file = $wp_list_table->get_main_page(); + $sendback = remove_query_arg( array( 'deleted', 'ids', 'changed', 'bulk_action' ), wp_get_referer() ); + + if ( ! $sendback ) { + $sendback = admin_url( $parent_file ); + } + + $sendback = add_query_arg( 'paged', $pagenum, $sendback ); + $shipment_ids = array(); + + if ( isset( $_REQUEST['ids'] ) ) { + $shipment_ids = array_map( 'absint', explode( ',', wp_unslash( $_REQUEST['ids'] ) ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + } elseif ( ! empty( $_REQUEST['shipment'] ) ) { + $shipment_ids = array_map( 'absint', wp_unslash( $_REQUEST['shipment'] ) ); + } + + if ( ! empty( $shipment_ids ) ) { + $sendback = $wp_list_table->handle_bulk_actions( $doaction, $shipment_ids, $sendback ); + } + + $sendback = remove_query_arg( array( 'action', 'action2', '_status', 'bulk_edit', 'shipment' ), $sendback ); + + wp_safe_redirect( esc_url_raw( $sendback ) ); + exit(); + + } elseif ( ! empty( $_REQUEST['_wp_http_referer'] ) ) { + wp_safe_redirect( esc_url_raw( remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) ) ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated + exit; + } + + $wp_list_table->set_bulk_notice(); + $wp_list_table->prepare_items(); + + add_screen_option( 'per_page' ); + } + + public static function setup_shipments_table() { + $table = new Table(); + + self::setup_table( $table ); + } + + public static function setup_returns_table() { + $table = new ReturnTable( array( 'type' => 'return' ) ); + + self::setup_table( $table ); + } + + public static function shipments_page() { + global $wp_list_table; + + ?> +
+

+
+ + output_notice(); + $_SERVER['REQUEST_URI'] = remove_query_arg( array( 'updated', 'changed', 'deleted', 'trashed', 'untrashed' ), ( isset( $_SERVER['REQUEST_URI'] ) ? esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : admin_url( 'admin.php?page=wc-gzd-shipments' ) ) ); + ?> + + views(); ?> + +
+ + search_box( _x( 'Search shipments', 'shipments', 'woocommerce-germanized' ), 'shipment' ); ?> + + + + + + + + display(); ?> +
+ +
+
+
+ +
+

+
+ + output_notice(); + $_SERVER['REQUEST_URI'] = remove_query_arg( array( 'updated', 'changed', 'deleted', 'trashed', 'untrashed' ), ( isset( $_SERVER['REQUEST_URI'] ) ? esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : admin_url( 'admin.php?page=wc-gzd-shipments' ) ) ); + ?> + + views(); ?> + +
+ + search_box( _x( 'Search returns', 'shipments', 'woocommerce-germanized' ), 'shipment' ); ?> + + + + + + + + display(); ?> +
+ +
+
+
+ id : ''; + $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; + + // Register admin styles. + wp_register_style( 'woocommerce_gzd_shipments_admin', Package::get_assets_url() . '/css/admin' . $suffix . '.css', array( 'woocommerce_admin_styles' ), Package::get_version() ); + + // Admin styles for WC pages only. + if ( in_array( $screen_id, self::get_screen_ids(), true ) ) { + wp_enqueue_style( 'woocommerce_gzd_shipments_admin' ); + } + + if ( 'woocommerce_page_wc-settings' === $screen_id && isset( $_GET['tab'] ) && in_array( $_GET['tab'], array( 'germanized-shipments', 'germanized-shipping_provider' ), true ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + wp_enqueue_style( 'woocommerce_gzd_shipments_admin' ); + } + + // Shipping zone methods + if ( 'woocommerce_page_wc-settings' === $screen_id && isset( $_GET['tab'] ) && 'shipping' === $_GET['tab'] && isset( $_GET['zone_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + wp_enqueue_style( 'woocommerce_gzd_shipments_admin' ); + } + } + + public static function admin_scripts() { + global $post; + + $screen = get_current_screen(); + $screen_id = $screen ? $screen->id : ''; + $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; + + wp_register_script( 'wc-gzd-admin-shipment-label-backbone', Package::get_assets_url() . '/js/admin-shipment-label-backbone' . $suffix . '.js', array( 'jquery', 'woocommerce_admin', 'wc-backbone-modal' ), Package::get_version() ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.NotInFooter + wp_register_script( 'wc-gzd-admin-shipment', Package::get_assets_url() . '/js/admin-shipment' . $suffix . '.js', array( 'wc-gzd-admin-shipment-label-backbone' ), Package::get_version() ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.NotInFooter + wp_register_script( 'wc-gzd-admin-shipments', Package::get_assets_url() . '/js/admin-shipments' . $suffix . '.js', array( 'wc-admin-order-meta-boxes', 'wc-gzd-admin-shipment' ), Package::get_version() ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.NotInFooter + wp_register_script( 'wc-gzd-admin-shipments-table', Package::get_assets_url() . '/js/admin-shipments-table' . $suffix . '.js', array( 'woocommerce_admin', 'wc-gzd-admin-shipment-label-backbone' ), Package::get_version() ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.NotInFooter + wp_register_script( 'wc-gzd-admin-shipping-providers', Package::get_assets_url() . '/js/admin-shipping-providers' . $suffix . '.js', array( 'jquery' ), Package::get_version() ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.NotInFooter + wp_register_script( 'wc-gzd-admin-shipping-provider-method', Package::get_assets_url() . '/js/admin-shipping-provider-method' . $suffix . '.js', array( 'jquery' ), Package::get_version() ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.NotInFooter + + // Orders. + if ( in_array( str_replace( 'edit-', '', $screen_id ), wc_get_order_types( 'order-meta-boxes' ), true ) ) { + + wp_enqueue_script( 'wc-gzd-admin-shipments' ); + wp_enqueue_script( 'wc-gzd-admin-shipment' ); + + wp_localize_script( + 'wc-gzd-admin-shipments', + 'wc_gzd_admin_shipments_params', + array( + 'ajax_url' => admin_url( 'admin-ajax.php' ), + 'edit_shipments_nonce' => wp_create_nonce( 'edit-shipments' ), + 'order_id' => isset( $post->ID ) ? $post->ID : '', + 'shipment_locked_excluded_fields' => array( 'status' ), + 'i18n_remove_shipment_notice' => _x( 'Do you really want to delete the shipment?', 'shipments', 'woocommerce-germanized' ), + 'remove_label_nonce' => wp_create_nonce( 'remove-shipment-label' ), + 'edit_label_nonce' => wp_create_nonce( 'edit-shipment-label' ), + 'send_return_notification_nonce' => wp_create_nonce( 'send-return-shipment-notification' ), + 'refresh_packaging_nonce' => wp_create_nonce( 'refresh-shipment-packaging' ), + 'confirm_return_request_nonce' => wp_create_nonce( 'confirm-return-request' ), + 'i18n_remove_label_notice' => _x( 'Do you really want to delete the label?', 'shipments', 'woocommerce-germanized' ), + 'i18n_create_label_enabled' => _x( 'Create new label', 'shipments', 'woocommerce-germanized' ), + 'i18n_create_label_disabled' => _x( 'Please save the shipment before creating a new label', 'shipments', 'woocommerce-germanized' ), + ) + ); + } + + // Table + if ( 'woocommerce_page_wc-gzd-shipments' === $screen_id || 'woocommerce_page_wc-gzd-return-shipments' === $screen_id ) { + wp_enqueue_script( 'wc-gzd-admin-shipments-table' ); + + $bulk_actions = array(); + + foreach ( self::get_bulk_action_handlers() as $handler ) { + $bulk_actions[ sanitize_key( $handler->get_action() ) ] = array( + 'title' => $handler->get_title(), + 'nonce' => wp_create_nonce( $handler->get_nonce_name() ), + ); + } + + wp_localize_script( + 'wc-gzd-admin-shipments-table', + 'wc_gzd_admin_shipments_table_params', + array( + 'ajax_url' => admin_url( 'admin-ajax.php' ), + 'search_orders_nonce' => wp_create_nonce( 'search-orders' ), + 'bulk_actions' => $bulk_actions, + ) + ); + } + + wp_localize_script( + 'wc-gzd-admin-shipment-label-backbone', + 'wc_gzd_admin_shipment_label_backbone_params', + array( + 'ajax_url' => admin_url( 'admin-ajax.php' ), + 'create_label_form_nonce' => wp_create_nonce( 'create-shipment-label-form' ), + 'create_label_nonce' => wp_create_nonce( 'create-shipment-label' ), + ) + ); + + // Shipping provider settings + if ( 'woocommerce_page_wc-settings' === $screen_id && isset( $_GET['tab'] ) && 'germanized-shipping_provider' === $_GET['tab'] && empty( $_GET['provider'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + wp_enqueue_script( 'wc-gzd-admin-shipping-providers' ); + + wp_localize_script( + 'wc-gzd-admin-shipping-providers', + 'wc_gzd_admin_shipping_providers_params', + array( + 'ajax_url' => admin_url( 'admin-ajax.php' ), + 'edit_shipping_providers_nonce' => wp_create_nonce( 'edit-shipping-providers' ), + 'remove_shipping_provider_nonce' => wp_create_nonce( 'remove-shipping-provider' ), + 'i18n_remove_shipping_provider_notice' => _x( 'Do you really want to delete the shipping provider? Some of your existing shipments might be linked to that provider and might need adjustments.', 'shipments', 'woocommerce-germanized' ), + ) + ); + } + + // Shipping provider method + if ( 'woocommerce_page_wc-settings' === $screen_id && isset( $_GET['tab'] ) && 'shipping' === $_GET['tab'] && ( isset( $_GET['zone_id'] ) || isset( $_GET['instance_id'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + wp_enqueue_script( 'wc-gzd-admin-shipping-provider-method' ); + $providers = array_filter( array_keys( wc_gzd_get_shipping_provider_select() ) ); + + wp_localize_script( + 'wc-gzd-admin-shipping-provider-method', + 'wc_gzd_admin_shipping_provider_method_params', + array( + 'shipping_providers' => $providers, + ) + ); + } + } + + /** + * @return BulkActionHandler[] $handler + */ + public static function get_bulk_action_handlers() { + if ( is_null( self::$bulk_handlers ) ) { + + self::$bulk_handlers = array(); + + /** + * Filter to register new BulkActionHandler for certain Shipment bulk actions. + * + * @param array $handlers Array containing key => classname. + * + * @since 3.0.0 + * @package Vendidero/Germanized/Shipments + */ + $handlers = apply_filters( + 'woocommerce_gzd_shipments_table_bulk_action_handlers', + array( + 'labels' => '\Vendidero\Germanized\Shipments\Admin\BulkLabel', + ) + ); + + foreach ( $handlers as $key => $handler ) { + self::$bulk_handlers[ $key ] = new $handler(); + } + } + + return self::$bulk_handlers; + } + + public static function get_bulk_action_handler( $action ) { + $handlers = self::get_bulk_action_handlers(); + + return array_key_exists( $action, $handlers ) ? $handlers[ $action ] : false; + } + + public static function get_screen_ids() { + + $screen_ids = array( + 'woocommerce_page_wc-gzd-shipments', + 'woocommerce_page_wc-gzd-return-shipments', + ); + + foreach ( wc_get_order_types() as $type ) { + $screen_ids[] = $type; + $screen_ids[] = 'edit-' . $type; + } + + return $screen_ids; + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Admin/BulkActionHandler.php b/packages/woocommerce-germanized-shipments/src/Admin/BulkActionHandler.php new file mode 100644 index 000000000..805ed7d7b --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Admin/BulkActionHandler.php @@ -0,0 +1,163 @@ +notices = array_filter( (array) get_user_meta( get_current_user_id(), $this->get_notice_option_name(), true ) ); + } + + protected function get_notice_option_name() { + $action = sanitize_key( $this->get_action() ); + + return "woocommerce_gzd_shipments_{$action}_bulk_notices"; + } + + abstract public function get_title(); + + public function get_nonce_name() { + $action = sanitize_key( $this->get_action() ); + + return "woocommerce_gzd_shipments_{$action}"; + } + + public function get_shipment_type() { + return $this->type; + } + + public function set_shipment_type( $type ) { + $this->type = $type; + } + + public function get_success_redirect_url() { + $page = 'wc-gzd-shipments'; + + if ( 'simple' !== $this->get_shipment_type() ) { + $page = 'wc-gzd-' . $this->get_shipment_type() . '-shipments'; + } + + return admin_url( 'admin.php?page=' . $page . '&bulk_action_handling=finished¤t_bulk_action=' . sanitize_key( $this->get_action() ) ); + } + + public function get_step() { + return $this->step; + } + + public function set_step( $step ) { + $this->step = $step; + } + + public function get_notices( $type = 'error' ) { + $notices = array_key_exists( $type, $this->notices ) ? $this->notices[ $type ] : array(); + + return $notices; + } + + public function get_success_message() { + return _x( 'Successfully processed shipments.', 'shipments', 'woocommerce-germanized' ); + } + + public function admin_handled() { + + } + + public function admin_after_error() { + + } + + public function add_notice( $notice, $type = 'error' ) { + if ( ! isset( $this->notices[ $type ] ) ) { + $this->notices[ $type ] = array(); + } + + $this->notices[ $type ][] = $notice; + } + + public function update_notices() { + update_user_meta( get_current_user_id(), $this->get_notice_option_name(), $this->notices ); + } + + public function reset( $is_new = false ) { + delete_user_meta( get_current_user_id(), $this->get_notice_option_name() ); + } + + abstract public function get_action(); + + public function get_max_step() { + return (int) ceil( count( $this->get_ids() ) / $this->get_limit() ); + } + + abstract public function get_limit(); + + public function get_total() { + return count( $this->get_ids() ); + } + + abstract public function handle(); + + public function set_ids( $ids ) { + $this->ids = $ids; + } + + public function get_ids() { + return $this->ids; + } + + public function get_current_ids() { + return array_slice( $this->get_ids(), ( $this->get_step() - 1 ) * $this->get_limit(), $this->get_limit() ); + } + + /** + * Get count of records exported. + * + * @since 3.0.6 + * @return int + */ + public function get_total_processed() { + return ( $this->get_step() * $this->get_limit() ); + } + + /** + * Get total % complete. + * + * @since 3.0.6 + * @return int + */ + public function get_percent_complete() { + return floor( ( $this->get_total_processed() / $this->get_total() ) * 100 ); + } + + public function is_last_step() { + $current_step = $this->get_step(); + $max_step = $this->get_max_step(); + + if ( $max_step === $current_step ) { + return true; + } + + return false; + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Admin/BulkLabel.php b/packages/woocommerce-germanized-shipments/src/Admin/BulkLabel.php new file mode 100644 index 000000000..1ed41548b --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Admin/BulkLabel.php @@ -0,0 +1,199 @@ +get_file_option_name(), true ); + + if ( $file ) { + $uploads = Package::get_upload_dir(); + $path = trailingslashit( $uploads['basedir'] ) . $file; + + return $path; + } + + return ''; + } + + protected function update_file( $path ) { + update_user_meta( get_current_user_id(), $this->get_file_option_name(), $path ); + } + + protected function get_file_option_name() { + $action = sanitize_key( $this->get_action() ); + + return "woocommerce_gzd_shipments_{$action}_bulk_path"; + } + + public function get_filename() { + if ( $file = $this->get_file() ) { + return basename( $file ); + } + + return ''; + } + + public function reset( $is_new = false ) { + parent::reset( $is_new ); + + if ( $is_new ) { + delete_user_meta( get_current_user_id(), $this->get_file_option_name() ); + delete_user_meta( get_current_user_id(), $this->get_files_option_name() ); + } + } + + protected function get_download_button() { + $download_button = ''; + + if ( ( $path = $this->get_file() ) && file_exists( $path ) ) { + + $download_url = add_query_arg( + array( + 'action' => 'wc-gzd-download-export-shipment-label', + 'force' => 'no', + ), + wp_nonce_url( admin_url(), 'download-export-shipment-label' ) + ); + + $download_button = '' . esc_html_x( 'Download labels', 'shipments', 'woocommerce-germanized' ) . ''; + } + + return $download_button; + } + + public function get_success_message() { + $download_button = $this->get_download_button(); + + if ( empty( $download_button ) ) { + return sprintf( _x( 'The chosen shipments were not suitable for automatic label creation. Please check the shipping provider option of the corresponding shipments.', 'shipments', 'woocommerce-germanized' ), $download_button ); + } else { + return sprintf( _x( 'Successfully generated labels. %s', 'shipments', 'woocommerce-germanized' ), $download_button ); + } + } + + public function admin_after_error() { + $download_button = $this->get_download_button(); + + if ( ! empty( $download_button ) ) { + echo '

' . sprintf( esc_html_x( 'Labels partially generated. %s', 'shipments', 'woocommerce-germanized' ), $download_button ) . '

'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + } + } + + protected function get_files_option_name() { + $action = sanitize_key( $this->get_action() ); + + return "woocommerce_gzd_shipments_{$action}_bulk_files"; + } + + protected function get_files() { + $files = get_user_meta( get_current_user_id(), $this->get_files_option_name(), true ); + + if ( empty( $files ) || ! is_array( $files ) ) { + $files = array(); + } + + return $files; + } + + protected function add_file( $path ) { + $files = $this->get_files(); + $files[] = $path; + + update_user_meta( get_current_user_id(), $this->get_files_option_name(), $files ); + } + + public function handle() { + $current = $this->get_current_ids(); + + if ( ! empty( $current ) ) { + foreach ( $current as $shipment_id ) { + $label = false; + + if ( $shipment = wc_gzd_get_shipment( $shipment_id ) ) { + if ( $shipment->supports_label() ) { + if ( $shipment->needs_label() ) { + $result = $shipment->create_label(); + + if ( is_wp_error( $result ) ) { + $this->add_notice( sprintf( _x( 'Error while creating label for %1$s: %2$s', 'shipments', 'woocommerce-germanized' ), '' . sprintf( _x( 'shipment #%d', 'shipments', 'woocommerce-germanized' ), $shipment_id ) . '', $result->get_error_message() ), 'error' ); + } else { + $label = $shipment->get_label(); + } + } else { + $label = $shipment->get_label(); + } + } + } + + if ( $label ) { + $this->add_file( $label->get_file() ); + } + } + } + + if ( $this->is_last_step() ) { + try { + $files = $this->get_files(); + $pdf = new PDFMerger(); + + if ( ! empty( $files ) ) { + foreach ( $files as $file ) { + if ( ! file_exists( $file ) ) { + continue; + } + + $pdf->add( $file ); + } + + /** + * Filter to adjust the default filename chosen for bulk exporting shipment labels. + * + * @param string $filename The filename. + * @param BulkLabel $this The `BulkLabel instance. + * + * @since 3.0.0 + * @package Vendidero/Germanized/shipments + */ + $filename = apply_filters( 'woocommerce_gzd_shipment_labels_bulk_filename', 'export.pdf', $this ); + $file = $pdf->output( $filename, 'S' ); + + if ( $path = wc_gzd_shipments_upload_data( $filename, $file ) ) { + $this->update_file( $path ); + } + } + } catch ( Exception $e ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch + } + } + + $this->update_notices(); + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Admin/MetaBox.php b/packages/woocommerce-germanized-shipments/src/Admin/MetaBox.php new file mode 100644 index 000000000..8e372b7fd --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Admin/MetaBox.php @@ -0,0 +1,172 @@ +get_shipments() as $shipment ) { + + $id = $shipment->get_id(); + $props = array(); + + // Update items + self::refresh_shipment_items( $order, $shipment ); + + // Do only update props if they exist + if ( isset( $_POST['shipment_weight'][ $id ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing + $props['weight'] = wc_clean( wp_unslash( $_POST['shipment_weight'][ $id ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing + } + + if ( isset( $_POST['shipment_length'][ $id ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing + $props['length'] = wc_clean( wp_unslash( $_POST['shipment_length'][ $id ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing + } + + if ( isset( $_POST['shipment_width'][ $id ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing + $props['width'] = wc_clean( wp_unslash( $_POST['shipment_width'][ $id ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing + } + + if ( isset( $_POST['shipment_height'][ $id ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing + $props['height'] = wc_clean( wp_unslash( $_POST['shipment_height'][ $id ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing + } + + if ( isset( $_POST['shipment_shipping_method'][ $id ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing + $props['shipping_method'] = wc_clean( wp_unslash( $_POST['shipment_shipping_method'][ $id ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing + } + + if ( isset( $_POST['shipment_tracking_id'][ $id ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing + $props['tracking_id'] = wc_clean( wp_unslash( $_POST['shipment_tracking_id'][ $id ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing + } + + if ( isset( $_POST['shipment_packaging_id'][ $id ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing + $props['packaging_id'] = wc_clean( wp_unslash( $_POST['shipment_packaging_id'][ $id ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing + } + + if ( isset( $_POST['shipment_shipping_provider'][ $id ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing + $provider = wc_clean( wp_unslash( $_POST['shipment_shipping_provider'][ $id ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing + $providers = wc_gzd_get_shipping_providers(); + + if ( empty( $provider ) || array_key_exists( $provider, $providers ) ) { + $props['shipping_provider'] = $provider; + } + } + + $new_status = isset( $_POST['shipment_status'][ $id ] ) ? str_replace( 'gzd-', '', wc_clean( wp_unslash( $_POST['shipment_status'][ $id ] ) ) ) : 'draft'; // phpcs:ignore WordPress.Security.NonceVerification.Missing + + // Sync the shipment - make sure gets refresh on status switch (e.g. from shipped to processing) + if ( $shipment->is_editable() || in_array( $new_status, wc_gzd_get_shipment_editable_statuses(), true ) ) { + $shipment->sync( $props ); + } + } + } + + /** + * @param Order $order + * @param bool $shipment + */ + public static function refresh_shipment_items( &$order, &$shipment = false ) { + $shipments = $shipment ? array( $shipment ) : $order->get_shipments(); + + foreach ( $shipments as $shipment ) { + $id = $shipment->get_id(); + + if ( ! $shipment->is_editable() ) { + continue; + } + + // Update items + foreach ( $shipment->get_items() as $item ) { + $item_id = $item->get_id(); + $props = array(); + + // Set quantity to 1 by default + if ( $shipment->is_editable() ) { + $props['quantity'] = 1; + } + + if ( isset( $_POST['shipment_item'][ $id ]['quantity'][ $item_id ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing + $props['quantity'] = absint( wp_unslash( $_POST['shipment_item'][ $id ]['quantity'][ $item_id ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing + } + + if ( isset( $_POST['shipment_item'][ $id ]['return_reason_code'][ $item_id ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing + $props['return_reason_code'] = wc_clean( wp_unslash( $_POST['shipment_item'][ $id ]['return_reason_code'][ $item_id ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing + } + + $item->sync( $props ); + } + } + } + + /** + * @param Order $order + */ + public static function refresh_status( &$order ) { + + foreach ( $order->get_shipments() as $shipment ) { + + $id = $shipment->get_id(); + $status = isset( $_POST['shipment_status'][ $id ] ) ? wc_clean( wp_unslash( $_POST['shipment_status'][ $id ] ) ) : 'draft'; // phpcs:ignore WordPress.Security.NonceVerification.Missing + + if ( ! wc_gzd_is_shipment_status( $status ) ) { + $status = 'draft'; + } + + $shipment->set_status( $status ); + } + } + + /** + * Output the metabox. + * + * @param WP_Post $post + */ + public static function output( $post ) { + global $post, $thepostid, $theorder; + + if ( ! is_int( $thepostid ) ) { + $thepostid = $post->ID; + } + + if ( ! is_object( $theorder ) ) { + $theorder = wc_get_order( $thepostid ); + } + + $order = $theorder; + $order_shipment = wc_gzd_get_shipment_order( $order ); + $active_shipment = isset( $_GET['shipment_id'] ) ? absint( $_GET['shipment_id'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended + + include Package::get_path() . '/includes/admin/views/html-order-shipments.php'; + } + + /** + * Save meta box data. + * + * @param int $post_id + */ + public static function save( $order_id ) { + // Get order object. + $order_shipment = wc_gzd_get_shipment_order( $order_id ); + + self::refresh_shipments( $order_shipment ); + + $order_shipment->validate_shipments( array( 'save' => false ) ); + + // Refresh status just before saving + self::refresh_status( $order_shipment ); + + $order_shipment->save(); + } +} diff --git a/packages/woocommerce-germanized-shipments/src/Admin/ProviderSettings.php b/packages/woocommerce-germanized-shipments/src/Admin/ProviderSettings.php new file mode 100644 index 000000000..56218e2a0 --- /dev/null +++ b/packages/woocommerce-germanized-shipments/src/Admin/ProviderSettings.php @@ -0,0 +1,260 @@ +get_shipping_providers(); + + if ( ! empty( $provider_name ) && 'new' !== $provider_name ) { + $provider = $helper->get_shipping_provider( $provider_name ); + } else { + $provider = new Simple(); + } + } + + return $provider; + } + + public static function get_help_link() { + if ( $provider = self::get_current_provider() ) { + return $provider->get_help_link(); + } else { + return 'https://vendidero.de/dokument/versanddienstleister-verwalten'; + } + } + + public static function get_next_pointers_link( $provider_name = false ) { + $providers = wc_gzd_get_shipping_providers(); + $next_url = admin_url( 'admin.php?page=wc-settings&tab=germanized-emails&tutorial=yes' ); + $provider_indexes = array(); + $provider_counts = array(); + $count = 0; + + foreach ( $providers as $provider_key => $provider ) { + if ( is_a( $provider, '\Vendidero\Germanized\Shipments\ShippingProvider\Auto' ) && ! empty( $provider->get_settings_help_pointers() ) ) { + $provider_indexes[ $provider_key ] = $count; + $provider_counts[ $count ] = $provider_key; + $count++; + } + } + + $next_index = isset( $provider_indexes[ $provider_name ] ) ? $provider_indexes[ $provider_name ] + 1 : -1; + + // By default use the first provider + if ( ! $provider_name ) { + $next_index = 0; + } + + if ( isset( $provider_counts[ $next_index ] ) ) { + $next_provider = $providers[ $provider_counts[ $next_index ] ]; + $next_url = add_query_arg( array( 'tutorial' => 'yes' ), $next_provider->get_edit_link() ); + } + + return $next_url; + } + + public static function get_pointers( $section ) { + $pointers = array(); + + if ( $provider = self::get_current_provider() ) { + if ( is_a( $provider, '\Vendidero\Germanized\Shipments\ShippingProvider\Auto' ) ) { + $pointers = $provider->get_settings_help_pointers( $section ); + } + } else { + $pointers = array( + 'pointers' => array( + 'provider' => array( + 'target' => '.wc-gzd-setting-tab-rows tr:first-child .wc-gzd-shipping-provider-title a.wc-gzd-shipping-provider-edit-link', + 'next' => 'activate', + 'next_url' => '', + 'next_trigger' => array(), + 'options' => array( + 'content' => '