diff --git a/none b/none
new file mode 100644
index 000000000..acee4c1a4
--- /dev/null
+++ b/none
@@ -0,0 +1,9 @@
+{
+ "version": 3,
+ "file": "assets/css/admin.css",
+ "sources": [
+ "assets/css/admin.scss"
+ ],
+ "names": [],
+ "mappings": "AAAA,AAAA,KAAK,AAAA,WAAW,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,AAAA,WAAW,CAAC;EAClC,MAAM,EAAE,YAAY;EACpB,OAAO,EAAE,YAAY,GACtB;;AAED,AAAA,wBAAwB,CAAC;EACvB,QAAQ,EAAE,QAAQ;EAClB,QAAQ,EAAE,MAAM,GA8BjB;EAhCD,AAIE,wBAJsB,CAItB,EAAE,CAAC;IACD,eAAe,EAAE,IAAI;IACrB,YAAY,EAAE,KAAK,GACpB;EAPH,AASE,wBATsB,CAStB,eAAe,CAAC;IACd,QAAQ,EAAE,MAAM;IAChB,KAAK,EAAE,KAAK;IACZ,OAAO,EAAE,gBAAgB;IACzB,UAAU,EAAE,KAAK;IACjB,SAAS,EAAE,IAAI;IACf,WAAW,EAAE,KAAK;IAClB,eAAe,EAAE,IAAI,GAStB;IAzBH,AAkBI,wBAlBoB,CAStB,eAAe,AASZ,QAAQ,CAAC;MACR,QAAQ,EAAE,QAAQ;MAClB,GAAG,EAAE,IAAI;MACT,IAAI,EAAE,KAAK;MACX,kBAAkB,EAAE,mBAAmB;MACvC,UAAU,EAAE,mBAAmB,GAChC;EAxBL,AA4BI,wBA5BoB,CA2BtB,CAAC,AAAA,OAAO,CACN,OAAO,CAAC;IACN,YAAY,EAAE,GAAG,GAClB;;AAIL,AAAA,wBAAwB,CAAC,gBAAgB,CAAC;EACxC,UAAU,EAAE,IAAI,GACjB;;AAED,AAAA,4BAA4B,CAAC,gBAAgB,CAAC;EAC5C,UAAU,EAAE,IAAI,GACjB;;AAED,AAAA,8BAA8B,CAAC;EAC7B,UAAU,EAAE,cAAc,GAC3B;;AAED,AAAA,kCAAkC,CAAC;EACjC,MAAM,EAAE,gBAAgB;EACxB,UAAU,EAAE,UAAU;EACtB,OAAO,EAAE,IAAI;EACb,OAAO,EAAE,QAAQ,GAClB;;AAED,AAAA,qBAAqB,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,0BAA0B,CAAE;EACpG,KAAK,EAAE,eAAe,GACvB;;AAED,AAAA,cAAc,CAAC;EACb,gBAAgB,EAAE,kBAAkB;EACpC,gBAAgB,EAAE,gDAAgD,CAAC,UAAU;EAC7E,KAAK,EAAE,eAAe;EACtB,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAE,KAAI,CAAC,oBAAoB,CAAC,UAAU;EACpG,MAAM,EAAE,gCAAgC;EACxC,WAAW,EAAE,eAAe;EAC5B,UAAU,EAAE,uFAAuF,GAgBpG;EAvBD,AASE,cATY,AASX,MAAM,CAAC;IACN,iBAAiB,EAAE,WAAW;IAC9B,SAAS,EAAE,WAAW;IACtB,MAAM,EAAE,OAAO,GAChB;EAbH,AAeE,cAfY,CAeZ,WAAW,CAAC;IACV,UAAU,EAAE,IAAI;IAChB,KAAK,EAAE,IAAI,GAKZ;IAtBH,AAmBI,cAnBU,CAeZ,WAAW,AAIR,MAAM,CAAC;MACN,KAAK,EAAE,IAAI,GACZ;;AAIL,AAAA,sBAAsB,CAAC,OAAO,CAAC;EAC7B,YAAY,EAAE,GAAG,GAClB;;AAED,AAAA,WAAW,CAAC;EACV,SAAS,EAAE,GAAG;EACd,aAAa,EAAE,GAAG;EAClB,WAAW,EAAE,GAAG;EAChB,KAAK,EAAE,IAAI;EACX,UAAU,EAAE,MAAM;EAClB,cAAc,EAAE,SAAS;EACzB,OAAO,EAAE,OAAO;EAChB,QAAQ,EAAE,QAAQ;EAClB,GAAG,EAAE,IAAI;EACT,UAAU,EAAE,IAAI;EAChB,UAAU,EAAE,MAAM;EAClB,OAAO,EAAE,YAAY;EACrB,eAAe,EAAE,IAAI,GACtB;;AAED,AAAA,2BAA2B,CAAC;EAC1B,UAAU,EAAE,OAAO;EACnB,MAAM,EAAE,cAAc;EACtB,KAAK,EAAE,IAAI;EACX,OAAO,EAAE,KAAK,GACf;;AAED,AAAA,WAAW,AAAA,QAAQ,CAAC;EAClB,KAAK,EAAE,IAAI,GACZ;;AAED,AAAA,WAAW,AAAA,MAAM,CAAC;EAChB,KAAK,EAAE,IAAI,GACZ;;AAED,AAAA,kBAAkB,CAAC,WAAW,CAAC;EAC7B,GAAG,EAAE,IAAI,GACV;;AAED,AAAA,CAAC,AAAA,uBAAuB,CAAC,KAAK,CAAC;EAC7B,OAAO,EAAE,gBAAgB;EACzB,aAAa,EAAE,GAAG,GACnB;;AAED,AAAA,uBAAuB,CAAC,KAAK,EAAE,uBAAuB,CAAC,KAAK,EAAE,uBAAuB,CAAC,oBAAoB,CAAC;EACzG,OAAO,EAAE,GAAG,GACb;;AAED,AAAA,KAAK,AAAA,mBAAmB,CAAC,EAAE,CAAC,EAAE,EAAE,KAAK,AAAA,mBAAmB,CAAC,EAAE,CAAC,EAAE,CAAC;EAC7D,OAAO,EAAE,GAAG;EACZ,SAAS,EAAE,KAAK,GACjB;;AAED,AAAA,KAAK,AAAA,mBAAmB,CAAC,EAAE,CAAC,EAAE,AAAA,YAAY,EAAE,KAAK,AAAA,mBAAmB,CAAC,EAAE,CAAC,EAAE,AAAA,YAAY,CAAC;EACrF,YAAY,EAAE,CAAC,GAChB;;AAED,AAAA,eAAe,CAAC;EACd,WAAW,EAAE,GAAG;EAChB,OAAO,EAAE,KAAK;EACd,KAAK,EAAE,IAAI;EACX,KAAK,EAAE,IAAI,GACZ;;AAED,AAAA,qBAAqB,AAAA,MAAM,CAAC;EAC1B,OAAO,EAAE,OAAO,GACjB;;AAED,AAAA,WAAW,CAAC,kBAAkB,CAAC,CAAC,AAAA,kBAAkB,CAAC;EACjD,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,CAAC;EACT,OAAO,EAAE,QAAQ;EACjB,MAAM,EAAE,SAAS;EACjB,QAAQ,EAAE,MAAM;EAChB,QAAQ,EAAE,QAAQ;EAClB,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,CAAC;EACT,KAAK,EAAE,KAAK,GACb;;AAED,AAAA,WAAW,CAAC,kBAAkB,CAAC,CAAC,AAAA,kBAAkB,AAAA,OAAO,CAAC;EACxD,WAAW,EAAE,SAAS;EACtB,OAAO,EAAE,OAAO;EAChB,QAAQ,EAAE,QAAQ;EAClB,GAAG,EAAE,CAAC;EACN,IAAI,EAAE,CAAC;EACP,UAAU,EAAE,MAAM;EAClB,cAAc,EAAE,GAAG;EACnB,WAAW,EAAE,IAAI;EACjB,SAAS,EAAE,IAAI;EACf,WAAW,EAAE,GAAG;EAChB,sBAAsB,EAAE,WAAW,GACpC;;AAED,AAAA,WAAW,CAAC,kBAAkB,CAAC,2BAA2B,EAAE,WAAW,CAAC,kBAAkB,CAAC,yBAAyB,EAAE,WAAW,CAAC,kBAAkB,CAAC,wBAAwB,EAAE,WAAW,CAAC,kBAAkB,CAAC,+BAA+B,CAAC;EAC5O,KAAK,EAAE,IAAI;EACX,KAAK,EAAE,eAAe,GACvB;;AAED,AAAA,WAAW,CAAC,kBAAkB,CAAC,2BAA2B,CAAC,KAAK,EAAE,WAAW,CAAC,kBAAkB,CAAC,yBAAyB,CAAC,KAAK,EAAE,WAAW,CAAC,kBAAkB,CAAC,wBAAwB,CAAC,KAAK,EAAE,WAAW,CAAC,kBAAkB,CAAC,+BAA+B,CAAC,KAAK,CAAC;EACpQ,KAAK,EAAE,IAAI,GACZ;;AAED,AAAA,WAAW,CAAC,uCAAuC,CAAC;EAClD,KAAK,EAAE,IAAI;EACX,KAAK,EAAE,eAAe,GACvB;;AAED,AAAA,gBAAgB,CAAC;EACf,KAAK,EAAE,GAAG,GACX;;AAED,AAAA,mBAAmB,CAAC;EAClB,WAAW,EAAE,GAAG,GACjB;;AAED,AAAA,kBAAkB,CAAC;EACjB,KAAK,EAAE,KAAK,GACb;;AAED,AAAA,cAAc,CAAC,IAAI,CAAC;EAClB,OAAO,EAAE,KAAK;EACd,WAAW,EAAE,OAAO;EACpB,QAAQ,EAAE,QAAQ;EAClB,OAAO,EAAE,CAAC,CAAA,UAAU;EACpB,MAAM,EAAE,GAAG,CAAA,UAAU;EACrB,KAAK,EAAE,GAAG,GACX;;AAED,AAAA,cAAc,CAAC,IAAI,AAAA,MAAM,CAAC;EACxB,OAAO,EAAE,OAAO;EAChB,WAAW,EAAE,WAAW;EACxB,WAAW,EAAE,CAAC;EACd,QAAQ,EAAE,QAAQ;EAClB,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;EACZ,KAAK,EAAE,IAAI;EACX,YAAY,EAAE,MAAM;EACpB,cAAc,EAAE,IAAI;EACpB,sBAAsB,EAAE,WAAW;EACnC,GAAG,EAAE,CAAC;EACN,IAAI,EAAE,CAAC;EACP,WAAW,EAAE,IAAI;EACjB,MAAM,EAAE,CAAC;EACT,UAAU,EAAE,MAAM;EAClB,WAAW,EAAE,GAAG,GACjB;;AAED,AAAA,gCAAgC,CAAC;EAC/B,KAAK,EAAE,IAAI;EACX,KAAK,EAAE,IAAI;EACX,KAAK,EAAE,IAAI,GACZ"
+}
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index e97aeb1bd..64cb06fcc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,8 +1,12489 @@
{
"name": "woocommerce-germanized",
- "version": "3.2.3",
- "lockfileVersion": 1,
+ "version": "3.4.0",
+ "lockfileVersion": 2,
"requires": true,
+ "packages": {
+ "": {
+ "name": "woocommerce-germanized",
+ "version": "3.4.0",
+ "license": "GPL-3.0+",
+ "devDependencies": {
+ "autoprefixer": "9.6.1",
+ "babel": "6.23.0",
+ "babel-cli": "6.26.0",
+ "babel-eslint": "10.0.2",
+ "babel-plugin-add-module-exports": "1.0.2",
+ "babel-preset-es2015": "6.24.1",
+ "babel-preset-stage-2": "6.24.1",
+ "chai": "4.2.0",
+ "chai-as-promised": "7.1.1",
+ "config": "3.2.2",
+ "cross-env": "5.2.0",
+ "eslint": "6.5.1",
+ "eslint-config-wpcalypso": "4.0.1",
+ "eslint-plugin-wpcalypso": "4.1.0",
+ "grunt": "1.0.4",
+ "grunt-checktextdomain": "1.0.1",
+ "grunt-contrib-clean": "2.0.0",
+ "grunt-contrib-concat": "1.0.1",
+ "grunt-contrib-copy": "1.0.0",
+ "grunt-contrib-cssmin": "3.0.0",
+ "grunt-contrib-jshint": "2.1.0",
+ "grunt-contrib-uglify": "4.0.1",
+ "grunt-contrib-watch": "1.1.0",
+ "grunt-phpcs": "0.4.0",
+ "grunt-postcss": "0.9.0",
+ "grunt-prompt": "1.3.3",
+ "grunt-rtlcss": "2.0.1",
+ "grunt-sass": "3.0.2",
+ "grunt-shell": "3.0.1",
+ "grunt-stylelint": "0.11.1",
+ "grunt-wp-i18n": "1.0.3",
+ "istanbul": "1.0.0-alpha.2",
+ "mocha": "6.2.0",
+ "node-sass": ">=4.13.1",
+ "prettier": "github:automattic/calypso-prettier#c56b4251",
+ "spectre.css": "*",
+ "stylelint": "10.1.0",
+ "stylelint-config-wordpress": "14.0.0"
+ },
+ "engines": {
+ "node": ">=10.15.0",
+ "npm": ">=6.4.1"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
+ "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/highlight": "^7.10.4"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.12.3",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.3.tgz",
+ "integrity": "sha512-0qXcZYKZp3/6N2jKYVxZv0aNCsxTSVCiK72DTiTYZAu7sjg73W0/aynWjMbiGd87EQL4WyA8reiJVh92AVla9g==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.10.4",
+ "@babel/generator": "^7.12.1",
+ "@babel/helper-module-transforms": "^7.12.1",
+ "@babel/helpers": "^7.12.1",
+ "@babel/parser": "^7.12.3",
+ "@babel/template": "^7.10.4",
+ "@babel/traverse": "^7.12.1",
+ "@babel/types": "^7.12.1",
+ "convert-source-map": "^1.7.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.1",
+ "json5": "^2.1.2",
+ "lodash": "^4.17.19",
+ "resolve": "^1.3.2",
+ "semver": "^5.4.1",
+ "source-map": "^0.5.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core/node_modules/debug": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz",
+ "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ }
+ },
+ "node_modules/@babel/core/node_modules/json5": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz",
+ "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==",
+ "dev": true,
+ "dependencies": {
+ "minimist": "^1.2.5"
+ },
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/@babel/core/node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "node_modules/@babel/core/node_modules/source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.12.5",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.5.tgz",
+ "integrity": "sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.12.5",
+ "jsesc": "^2.5.1",
+ "source-map": "^0.5.0"
+ }
+ },
+ "node_modules/@babel/generator/node_modules/jsesc": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
+ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
+ "dev": true,
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/generator/node_modules/source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/@babel/helper-function-name": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz",
+ "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-get-function-arity": "^7.10.4",
+ "@babel/template": "^7.10.4",
+ "@babel/types": "^7.10.4"
+ }
+ },
+ "node_modules/@babel/helper-get-function-arity": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz",
+ "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.10.4"
+ }
+ },
+ "node_modules/@babel/helper-member-expression-to-functions": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.1.tgz",
+ "integrity": "sha512-k0CIe3tXUKTRSoEx1LQEPFU9vRQfqHtl+kf8eNnDqb4AUJEy5pz6aIiog+YWtVm2jpggjS1laH68bPsR+KWWPQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.12.1"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.12.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz",
+ "integrity": "sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.12.5"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz",
+ "integrity": "sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.12.1",
+ "@babel/helper-replace-supers": "^7.12.1",
+ "@babel/helper-simple-access": "^7.12.1",
+ "@babel/helper-split-export-declaration": "^7.11.0",
+ "@babel/helper-validator-identifier": "^7.10.4",
+ "@babel/template": "^7.10.4",
+ "@babel/traverse": "^7.12.1",
+ "@babel/types": "^7.12.1",
+ "lodash": "^4.17.19"
+ }
+ },
+ "node_modules/@babel/helper-optimise-call-expression": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz",
+ "integrity": "sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.10.4"
+ }
+ },
+ "node_modules/@babel/helper-replace-supers": {
+ "version": "7.12.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.5.tgz",
+ "integrity": "sha512-5YILoed0ZyIpF4gKcpZitEnXEJ9UoDRki1Ey6xz46rxOzfNMAhVIJMoune1hmPVxh40LRv1+oafz7UsWX+vyWA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-member-expression-to-functions": "^7.12.1",
+ "@babel/helper-optimise-call-expression": "^7.10.4",
+ "@babel/traverse": "^7.12.5",
+ "@babel/types": "^7.12.5"
+ }
+ },
+ "node_modules/@babel/helper-simple-access": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz",
+ "integrity": "sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.12.1"
+ }
+ },
+ "node_modules/@babel/helper-split-export-declaration": {
+ "version": "7.11.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz",
+ "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.11.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz",
+ "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==",
+ "dev": true
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.12.5",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.12.5.tgz",
+ "integrity": "sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/template": "^7.10.4",
+ "@babel/traverse": "^7.12.5",
+ "@babel/types": "^7.12.5"
+ }
+ },
+ "node_modules/@babel/highlight": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz",
+ "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.10.4",
+ "chalk": "^2.0.0",
+ "js-tokens": "^4.0.0"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.12.5",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.5.tgz",
+ "integrity": "sha512-FVM6RZQ0mn2KCf1VUED7KepYeUWoVShczewOCfm3nzoBybaih51h+sYVVGthW9M6lPByEPTQf+xm27PBdlpwmQ==",
+ "dev": true,
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz",
+ "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.10.4",
+ "@babel/parser": "^7.10.4",
+ "@babel/types": "^7.10.4"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.12.5",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.5.tgz",
+ "integrity": "sha512-xa15FbQnias7z9a62LwYAA5SZZPkHIXpd42C6uW68o8uTuua96FHZy1y61Va5P/i83FAAcMpW8+A/QayntzuqA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.10.4",
+ "@babel/generator": "^7.12.5",
+ "@babel/helper-function-name": "^7.10.4",
+ "@babel/helper-split-export-declaration": "^7.11.0",
+ "@babel/parser": "^7.12.5",
+ "@babel/types": "^7.12.5",
+ "debug": "^4.1.0",
+ "globals": "^11.1.0",
+ "lodash": "^4.17.19"
+ }
+ },
+ "node_modules/@babel/traverse/node_modules/debug": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz",
+ "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ }
+ },
+ "node_modules/@babel/traverse/node_modules/globals": {
+ "version": "11.12.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/traverse/node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "node_modules/@babel/types": {
+ "version": "7.12.6",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.6.tgz",
+ "integrity": "sha512-hwyjw6GvjBLiyy3W0YQf0Z5Zf4NpYejUnKFcfcUhZCSffoBBp30w6wP2Wn6pk31jMYZvcOrB/1b7cGXvEoKogA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.10.4",
+ "lodash": "^4.17.19",
+ "to-fast-properties": "^2.0.0"
+ }
+ },
+ "node_modules/@babel/types/node_modules/to-fast-properties": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
+ "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@choojs/findup": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/@choojs/findup/-/findup-0.2.1.tgz",
+ "integrity": "sha512-YstAqNb0MCN8PjdLCDfRsBcGVRN41f3vgLvaI0IrIcBp4AqILRSS0DeWNGkicC+f/zRIPJLc+9RURVSepwvfBw==",
+ "dev": true,
+ "dependencies": {
+ "commander": "^2.15.1"
+ },
+ "bin": {
+ "findup": "bin/findup.js"
+ }
+ },
+ "node_modules/@mrmlnc/readdir-enhanced": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
+ "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==",
+ "dev": true,
+ "dependencies": {
+ "call-me-maybe": "^1.0.1",
+ "glob-to-regexp": "^0.3.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@nodelib/fs.stat": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz",
+ "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/@types/glob": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz",
+ "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==",
+ "dev": true,
+ "dependencies": {
+ "@types/minimatch": "*",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/minimatch": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
+ "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==",
+ "dev": true
+ },
+ "node_modules/@types/node": {
+ "version": "14.14.7",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.7.tgz",
+ "integrity": "sha512-Zw1vhUSQZYw+7u5dAwNbIA9TuTotpzY/OF7sJM9FqPOF3SPjKnxrjoTktXDZgUjybf4cWVBP7O8wvKdSaGHweg==",
+ "dev": true
+ },
+ "node_modules/@types/unist": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz",
+ "integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==",
+ "dev": true
+ },
+ "node_modules/@types/vfile": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@types/vfile/-/vfile-3.0.2.tgz",
+ "integrity": "sha512-b3nLFGaGkJ9rzOcuXRfHkZMdjsawuDD0ENL9fzTophtBg8FJHSGbH7daXkEpcwy3v7Xol3pAvsmlYyFhR4pqJw==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*",
+ "@types/unist": "*",
+ "@types/vfile-message": "*"
+ }
+ },
+ "node_modules/@types/vfile-message": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@types/vfile-message/-/vfile-message-2.0.0.tgz",
+ "integrity": "sha512-GpTIuDpb9u4zIO165fUy9+fXcULdD8HFRNli04GehoMVbeNq7D6OBnqSmg3lxZnC+UvgUhEWKxdKiwYUkGltIw==",
+ "dev": true,
+ "dependencies": {
+ "vfile-message": "*"
+ }
+ },
+ "node_modules/abbrev": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
+ "dev": true
+ },
+ "node_modules/acorn": {
+ "version": "7.4.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
+ "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
+ "dev": true,
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-jsx": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz",
+ "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==",
+ "dev": true
+ },
+ "node_modules/ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "node_modules/amdefine": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
+ "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4.2"
+ }
+ },
+ "node_modules/ansi-colors": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz",
+ "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/ansi-escapes": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz",
+ "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/anymatch": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz",
+ "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "micromatch": "^2.1.5",
+ "normalize-path": "^2.0.0"
+ }
+ },
+ "node_modules/append-transform": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-0.4.0.tgz",
+ "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=",
+ "dev": true,
+ "dependencies": {
+ "default-require-extensions": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/aproba": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
+ "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
+ "dev": true
+ },
+ "node_modules/are-we-there-yet": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
+ "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
+ "dev": true,
+ "dependencies": {
+ "delegates": "^1.0.0",
+ "readable-stream": "^2.0.6"
+ }
+ },
+ "node_modules/argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "dev": true,
+ "dependencies": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "node_modules/arr-diff": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
+ "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "arr-flatten": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/arr-flatten": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+ "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/arr-union": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/array-find-index": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
+ "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/array-union": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
+ "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
+ "dev": true,
+ "dependencies": {
+ "array-uniq": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/array-uniq": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
+ "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/array-unique": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
+ "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=",
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/arrify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
+ "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/asn1": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
+ "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
+ "dev": true,
+ "dependencies": {
+ "safer-buffer": "~2.1.0"
+ }
+ },
+ "node_modules/assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/assertion-error": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
+ "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/assign-symbols": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/astral-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
+ "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/async": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+ "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=",
+ "dev": true
+ },
+ "node_modules/async-each": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz",
+ "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==",
+ "dev": true,
+ "optional": true
+ },
+ "node_modules/async-foreach": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz",
+ "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
+ "dev": true
+ },
+ "node_modules/atob": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
+ "dev": true,
+ "bin": {
+ "atob": "bin/atob.js"
+ },
+ "engines": {
+ "node": ">= 4.5.0"
+ }
+ },
+ "node_modules/autoprefixer": {
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.6.1.tgz",
+ "integrity": "sha512-aVo5WxR3VyvyJxcJC3h4FKfwCQvQWb1tSI5VHNibddCVWrcD1NvlxEweg3TSgiPztMnWfjpy2FURKA2kvDE+Tw==",
+ "dev": true,
+ "dependencies": {
+ "browserslist": "^4.6.3",
+ "caniuse-lite": "^1.0.30000980",
+ "chalk": "^2.4.2",
+ "normalize-range": "^0.1.2",
+ "num2fraction": "^1.2.2",
+ "postcss": "^7.0.17",
+ "postcss-value-parser": "^4.0.0"
+ },
+ "bin": {
+ "autoprefixer": "bin/autoprefixer"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/aws-sign2": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/aws4": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
+ "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==",
+ "dev": true
+ },
+ "node_modules/babel": {
+ "version": "6.23.0",
+ "resolved": "https://registry.npmjs.org/babel/-/babel-6.23.0.tgz",
+ "integrity": "sha1-0NHn2APpdHZb7qMjLU4VPA77kPQ=",
+ "dev": true,
+ "bin": {
+ "babel": "lib/cli.js",
+ "babel-external-helpers": "lib/cli.js",
+ "babel-node": "lib/cli.js"
+ }
+ },
+ "node_modules/babel-cli": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-cli/-/babel-cli-6.26.0.tgz",
+ "integrity": "sha1-UCq1SHTX24itALiHoGODzgPQAvE=",
+ "dev": true,
+ "dependencies": {
+ "babel-core": "^6.26.0",
+ "babel-polyfill": "^6.26.0",
+ "babel-register": "^6.26.0",
+ "babel-runtime": "^6.26.0",
+ "commander": "^2.11.0",
+ "convert-source-map": "^1.5.0",
+ "fs-readdir-recursive": "^1.0.0",
+ "glob": "^7.1.2",
+ "lodash": "^4.17.4",
+ "output-file-sync": "^1.1.2",
+ "path-is-absolute": "^1.0.1",
+ "slash": "^1.0.0",
+ "source-map": "^0.5.6",
+ "v8flags": "^2.1.1"
+ },
+ "bin": {
+ "babel": "bin/babel.js",
+ "babel-doctor": "bin/babel-doctor.js",
+ "babel-external-helpers": "bin/babel-external-helpers.js",
+ "babel-node": "bin/babel-node.js"
+ },
+ "optionalDependencies": {
+ "chokidar": "^1.6.1"
+ }
+ },
+ "node_modules/babel-cli/node_modules/source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-code-frame": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
+ "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "esutils": "^2.0.2",
+ "js-tokens": "^3.0.2"
+ }
+ },
+ "node_modules/babel-code-frame/node_modules/ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-code-frame/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-code-frame/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/babel-core": {
+ "version": "6.26.3",
+ "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz",
+ "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==",
+ "dev": true,
+ "dependencies": {
+ "babel-code-frame": "^6.26.0",
+ "babel-generator": "^6.26.0",
+ "babel-helpers": "^6.24.1",
+ "babel-messages": "^6.23.0",
+ "babel-register": "^6.26.0",
+ "babel-runtime": "^6.26.0",
+ "babel-template": "^6.26.0",
+ "babel-traverse": "^6.26.0",
+ "babel-types": "^6.26.0",
+ "babylon": "^6.18.0",
+ "convert-source-map": "^1.5.1",
+ "debug": "^2.6.9",
+ "json5": "^0.5.1",
+ "lodash": "^4.17.4",
+ "minimatch": "^3.0.4",
+ "path-is-absolute": "^1.0.1",
+ "private": "^0.1.8",
+ "slash": "^1.0.0",
+ "source-map": "^0.5.7"
+ }
+ },
+ "node_modules/babel-core/node_modules/source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-eslint": {
+ "version": "10.0.2",
+ "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.0.2.tgz",
+ "integrity": "sha512-UdsurWPtgiPgpJ06ryUnuaSXC2s0WoSZnQmEpbAH65XZSdwowgN5MvyP7e88nW07FYXv72erVtpBkxyDVKhH1Q==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.0.0",
+ "@babel/parser": "^7.0.0",
+ "@babel/traverse": "^7.0.0",
+ "@babel/types": "^7.0.0",
+ "eslint-scope": "3.7.1",
+ "eslint-visitor-keys": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/babel-generator": {
+ "version": "6.26.1",
+ "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz",
+ "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==",
+ "dev": true,
+ "dependencies": {
+ "babel-messages": "^6.23.0",
+ "babel-runtime": "^6.26.0",
+ "babel-types": "^6.26.0",
+ "detect-indent": "^4.0.0",
+ "jsesc": "^1.3.0",
+ "lodash": "^4.17.4",
+ "source-map": "^0.5.7",
+ "trim-right": "^1.0.1"
+ }
+ },
+ "node_modules/babel-generator/node_modules/source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-helper-bindify-decorators": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz",
+ "integrity": "sha1-FMGeXxQte0fxmlJDHlKxzLxAozA=",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0",
+ "babel-traverse": "^6.24.1",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-helper-builder-binary-assignment-operator-visitor": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz",
+ "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-explode-assignable-expression": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-helper-call-delegate": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz",
+ "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-hoist-variables": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-traverse": "^6.24.1",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-helper-define-map": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz",
+ "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-function-name": "^6.24.1",
+ "babel-runtime": "^6.26.0",
+ "babel-types": "^6.26.0",
+ "lodash": "^4.17.4"
+ }
+ },
+ "node_modules/babel-helper-explode-assignable-expression": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz",
+ "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0",
+ "babel-traverse": "^6.24.1",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-helper-explode-class": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz",
+ "integrity": "sha1-fcKjkQ3uAHBW4eMdZAztPVTqqes=",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-bindify-decorators": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-traverse": "^6.24.1",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-helper-function-name": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz",
+ "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-get-function-arity": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1",
+ "babel-traverse": "^6.24.1",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-helper-get-function-arity": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz",
+ "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-helper-hoist-variables": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz",
+ "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-helper-optimise-call-expression": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz",
+ "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-helper-regex": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz",
+ "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.26.0",
+ "babel-types": "^6.26.0",
+ "lodash": "^4.17.4"
+ }
+ },
+ "node_modules/babel-helper-remap-async-to-generator": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz",
+ "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-function-name": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1",
+ "babel-traverse": "^6.24.1",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-helper-replace-supers": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz",
+ "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-optimise-call-expression": "^6.24.1",
+ "babel-messages": "^6.23.0",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1",
+ "babel-traverse": "^6.24.1",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-helpers": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz",
+ "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1"
+ }
+ },
+ "node_modules/babel-messages": {
+ "version": "6.23.0",
+ "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
+ "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/babel-plugin-add-module-exports/-/babel-plugin-add-module-exports-1.0.2.tgz",
+ "integrity": "sha512-4paN7RivvU3Rzju1vGSHWPjO8Y0rI6droWvSFKI6dvEQ4mvoV0zGojnlzVRfI6N8zISo6VERXt3coIuVmzuvNg==",
+ "dev": true,
+ "optionalDependencies": {
+ "chokidar": "^2.0.4"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/anymatch": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
+ "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "micromatch": "^3.1.4",
+ "normalize-path": "^2.1.1"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/anymatch/node_modules/normalize-path": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "remove-trailing-separator": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/arr-diff": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+ "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/array-unique": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/braces": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "arr-flatten": "^1.1.0",
+ "array-unique": "^0.3.2",
+ "extend-shallow": "^2.0.1",
+ "fill-range": "^4.0.0",
+ "isobject": "^3.0.1",
+ "repeat-element": "^1.1.2",
+ "snapdragon": "^0.8.1",
+ "snapdragon-node": "^2.0.1",
+ "split-string": "^3.0.2",
+ "to-regex": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/braces/node_modules/extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-extendable": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/chokidar": {
+ "version": "2.1.8",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
+ "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "anymatch": "^2.0.0",
+ "async-each": "^1.0.1",
+ "braces": "^2.3.2",
+ "fsevents": "^1.2.7",
+ "glob-parent": "^3.1.0",
+ "inherits": "^2.0.3",
+ "is-binary-path": "^1.0.0",
+ "is-glob": "^4.0.0",
+ "normalize-path": "^3.0.0",
+ "path-is-absolute": "^1.0.0",
+ "readdirp": "^2.2.1",
+ "upath": "^1.1.1"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/expand-brackets": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "debug": "^2.3.3",
+ "define-property": "^0.2.5",
+ "extend-shallow": "^2.0.1",
+ "posix-character-classes": "^0.1.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/expand-brackets/node_modules/define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-descriptor": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/expand-brackets/node_modules/extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-extendable": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/expand-brackets/node_modules/is-accessor-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/expand-brackets/node_modules/is-accessor-descriptor/node_modules/kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-buffer": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/expand-brackets/node_modules/is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/expand-brackets/node_modules/is-data-descriptor/node_modules/kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-buffer": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/expand-brackets/node_modules/is-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-accessor-descriptor": "^0.1.6",
+ "is-data-descriptor": "^0.1.4",
+ "kind-of": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/expand-brackets/node_modules/kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/extglob": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "array-unique": "^0.3.2",
+ "define-property": "^1.0.0",
+ "expand-brackets": "^2.1.4",
+ "extend-shallow": "^2.0.1",
+ "fragment-cache": "^0.2.1",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/extglob/node_modules/define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-descriptor": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/extglob/node_modules/extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-extendable": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/fill-range": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "extend-shallow": "^2.0.1",
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1",
+ "to-regex-range": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/fill-range/node_modules/extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-extendable": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/glob-parent": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
+ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-glob": "^3.1.0",
+ "path-dirname": "^1.0.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/glob-parent/node_modules/is-glob": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-extglob": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "kind-of": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "kind-of": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/is-glob": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
+ "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/is-number/node_modules/kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-buffer": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/kind-of": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/micromatch": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "arr-diff": "^4.0.0",
+ "array-unique": "^0.3.2",
+ "braces": "^2.3.1",
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "extglob": "^2.0.4",
+ "fragment-cache": "^0.2.1",
+ "kind-of": "^6.0.2",
+ "nanomatch": "^1.2.9",
+ "object.pick": "^1.3.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-add-module-exports/node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-check-es2015-constants": {
+ "version": "6.22.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz",
+ "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-syntax-async-functions": {
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz",
+ "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=",
+ "dev": true
+ },
+ "node_modules/babel-plugin-syntax-async-generators": {
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz",
+ "integrity": "sha1-a8lj67FuzLrmuStZbrfzXDQqi5o=",
+ "dev": true
+ },
+ "node_modules/babel-plugin-syntax-class-properties": {
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz",
+ "integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94=",
+ "dev": true
+ },
+ "node_modules/babel-plugin-syntax-decorators": {
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz",
+ "integrity": "sha1-MSVjtNvePMgGzuPkFszurd0RrAs=",
+ "dev": true
+ },
+ "node_modules/babel-plugin-syntax-dynamic-import": {
+ "version": "6.18.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz",
+ "integrity": "sha1-jWomIpyDdFqZgqRBBRVyyqF5sdo=",
+ "dev": true
+ },
+ "node_modules/babel-plugin-syntax-exponentiation-operator": {
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz",
+ "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=",
+ "dev": true
+ },
+ "node_modules/babel-plugin-syntax-object-rest-spread": {
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz",
+ "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=",
+ "dev": true
+ },
+ "node_modules/babel-plugin-syntax-trailing-function-commas": {
+ "version": "6.22.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz",
+ "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=",
+ "dev": true
+ },
+ "node_modules/babel-plugin-transform-async-generator-functions": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz",
+ "integrity": "sha1-8FiQAUX9PpkHpt3yjaWfIVJYpds=",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-remap-async-to-generator": "^6.24.1",
+ "babel-plugin-syntax-async-generators": "^6.5.0",
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-async-to-generator": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz",
+ "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-remap-async-to-generator": "^6.24.1",
+ "babel-plugin-syntax-async-functions": "^6.8.0",
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-class-properties": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz",
+ "integrity": "sha1-anl2PqYdM9NvN7YRqp3vgagbRqw=",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-function-name": "^6.24.1",
+ "babel-plugin-syntax-class-properties": "^6.8.0",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1"
+ }
+ },
+ "node_modules/babel-plugin-transform-decorators": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz",
+ "integrity": "sha1-eIAT2PjGtSIr33s0Q5Df13Vp4k0=",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-explode-class": "^6.24.1",
+ "babel-plugin-syntax-decorators": "^6.13.0",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-arrow-functions": {
+ "version": "6.22.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz",
+ "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-block-scoped-functions": {
+ "version": "6.22.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz",
+ "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-block-scoping": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz",
+ "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.26.0",
+ "babel-template": "^6.26.0",
+ "babel-traverse": "^6.26.0",
+ "babel-types": "^6.26.0",
+ "lodash": "^4.17.4"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-classes": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz",
+ "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-define-map": "^6.24.1",
+ "babel-helper-function-name": "^6.24.1",
+ "babel-helper-optimise-call-expression": "^6.24.1",
+ "babel-helper-replace-supers": "^6.24.1",
+ "babel-messages": "^6.23.0",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1",
+ "babel-traverse": "^6.24.1",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-computed-properties": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz",
+ "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-destructuring": {
+ "version": "6.23.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz",
+ "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-duplicate-keys": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz",
+ "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-for-of": {
+ "version": "6.23.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz",
+ "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-function-name": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz",
+ "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-function-name": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-literals": {
+ "version": "6.22.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz",
+ "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-modules-amd": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz",
+ "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=",
+ "dev": true,
+ "dependencies": {
+ "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-modules-commonjs": {
+ "version": "6.26.2",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz",
+ "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==",
+ "dev": true,
+ "dependencies": {
+ "babel-plugin-transform-strict-mode": "^6.24.1",
+ "babel-runtime": "^6.26.0",
+ "babel-template": "^6.26.0",
+ "babel-types": "^6.26.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-modules-systemjs": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz",
+ "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-hoist-variables": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-modules-umd": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz",
+ "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=",
+ "dev": true,
+ "dependencies": {
+ "babel-plugin-transform-es2015-modules-amd": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-object-super": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz",
+ "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-replace-supers": "^6.24.1",
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-parameters": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz",
+ "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-call-delegate": "^6.24.1",
+ "babel-helper-get-function-arity": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1",
+ "babel-traverse": "^6.24.1",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-shorthand-properties": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz",
+ "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-spread": {
+ "version": "6.22.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz",
+ "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-sticky-regex": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz",
+ "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-regex": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-template-literals": {
+ "version": "6.22.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz",
+ "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-typeof-symbol": {
+ "version": "6.23.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz",
+ "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-unicode-regex": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz",
+ "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-regex": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "regexpu-core": "^2.0.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-exponentiation-operator": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz",
+ "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-builder-binary-assignment-operator-visitor": "^6.24.1",
+ "babel-plugin-syntax-exponentiation-operator": "^6.8.0",
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-object-rest-spread": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz",
+ "integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=",
+ "dev": true,
+ "dependencies": {
+ "babel-plugin-syntax-object-rest-spread": "^6.8.0",
+ "babel-runtime": "^6.26.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-regenerator": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz",
+ "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=",
+ "dev": true,
+ "dependencies": {
+ "regenerator-transform": "^0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-strict-mode": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz",
+ "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-polyfill": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz",
+ "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.26.0",
+ "core-js": "^2.5.0",
+ "regenerator-runtime": "^0.10.5"
+ }
+ },
+ "node_modules/babel-polyfill/node_modules/regenerator-runtime": {
+ "version": "0.10.5",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz",
+ "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=",
+ "dev": true
+ },
+ "node_modules/babel-preset-es2015": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz",
+ "integrity": "sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk=",
+ "dev": true,
+ "dependencies": {
+ "babel-plugin-check-es2015-constants": "^6.22.0",
+ "babel-plugin-transform-es2015-arrow-functions": "^6.22.0",
+ "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0",
+ "babel-plugin-transform-es2015-block-scoping": "^6.24.1",
+ "babel-plugin-transform-es2015-classes": "^6.24.1",
+ "babel-plugin-transform-es2015-computed-properties": "^6.24.1",
+ "babel-plugin-transform-es2015-destructuring": "^6.22.0",
+ "babel-plugin-transform-es2015-duplicate-keys": "^6.24.1",
+ "babel-plugin-transform-es2015-for-of": "^6.22.0",
+ "babel-plugin-transform-es2015-function-name": "^6.24.1",
+ "babel-plugin-transform-es2015-literals": "^6.22.0",
+ "babel-plugin-transform-es2015-modules-amd": "^6.24.1",
+ "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1",
+ "babel-plugin-transform-es2015-modules-systemjs": "^6.24.1",
+ "babel-plugin-transform-es2015-modules-umd": "^6.24.1",
+ "babel-plugin-transform-es2015-object-super": "^6.24.1",
+ "babel-plugin-transform-es2015-parameters": "^6.24.1",
+ "babel-plugin-transform-es2015-shorthand-properties": "^6.24.1",
+ "babel-plugin-transform-es2015-spread": "^6.22.0",
+ "babel-plugin-transform-es2015-sticky-regex": "^6.24.1",
+ "babel-plugin-transform-es2015-template-literals": "^6.22.0",
+ "babel-plugin-transform-es2015-typeof-symbol": "^6.22.0",
+ "babel-plugin-transform-es2015-unicode-regex": "^6.24.1",
+ "babel-plugin-transform-regenerator": "^6.24.1"
+ }
+ },
+ "node_modules/babel-preset-stage-2": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz",
+ "integrity": "sha1-2eKWD7PXEYfw5k7sYrwHdnIZvcE=",
+ "dev": true,
+ "dependencies": {
+ "babel-plugin-syntax-dynamic-import": "^6.18.0",
+ "babel-plugin-transform-class-properties": "^6.24.1",
+ "babel-plugin-transform-decorators": "^6.24.1",
+ "babel-preset-stage-3": "^6.24.1"
+ }
+ },
+ "node_modules/babel-preset-stage-3": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz",
+ "integrity": "sha1-g2raCp56f6N8sTj7kyb4eTSkg5U=",
+ "dev": true,
+ "dependencies": {
+ "babel-plugin-syntax-trailing-function-commas": "^6.22.0",
+ "babel-plugin-transform-async-generator-functions": "^6.24.1",
+ "babel-plugin-transform-async-to-generator": "^6.24.1",
+ "babel-plugin-transform-exponentiation-operator": "^6.24.1",
+ "babel-plugin-transform-object-rest-spread": "^6.22.0"
+ }
+ },
+ "node_modules/babel-register": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz",
+ "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=",
+ "dev": true,
+ "dependencies": {
+ "babel-core": "^6.26.0",
+ "babel-runtime": "^6.26.0",
+ "core-js": "^2.5.0",
+ "home-or-tmp": "^2.0.0",
+ "lodash": "^4.17.4",
+ "mkdirp": "^0.5.1",
+ "source-map-support": "^0.4.15"
+ }
+ },
+ "node_modules/babel-runtime": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
+ "dev": true,
+ "dependencies": {
+ "core-js": "^2.4.0",
+ "regenerator-runtime": "^0.11.0"
+ }
+ },
+ "node_modules/babel-template": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz",
+ "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.26.0",
+ "babel-traverse": "^6.26.0",
+ "babel-types": "^6.26.0",
+ "babylon": "^6.18.0",
+ "lodash": "^4.17.4"
+ }
+ },
+ "node_modules/babel-traverse": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz",
+ "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=",
+ "dev": true,
+ "dependencies": {
+ "babel-code-frame": "^6.26.0",
+ "babel-messages": "^6.23.0",
+ "babel-runtime": "^6.26.0",
+ "babel-types": "^6.26.0",
+ "babylon": "^6.18.0",
+ "debug": "^2.6.8",
+ "globals": "^9.18.0",
+ "invariant": "^2.2.2",
+ "lodash": "^4.17.4"
+ }
+ },
+ "node_modules/babel-types": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
+ "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.26.0",
+ "esutils": "^2.0.2",
+ "lodash": "^4.17.4",
+ "to-fast-properties": "^1.0.3"
+ }
+ },
+ "node_modules/babylon": {
+ "version": "6.18.0",
+ "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
+ "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==",
+ "dev": true,
+ "bin": {
+ "babylon": "bin/babylon.js"
+ }
+ },
+ "node_modules/bail": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz",
+ "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==",
+ "dev": true
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+ "dev": true
+ },
+ "node_modules/base": {
+ "version": "0.11.2",
+ "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
+ "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
+ "dev": true,
+ "dependencies": {
+ "cache-base": "^1.0.1",
+ "class-utils": "^0.3.5",
+ "component-emitter": "^1.2.1",
+ "define-property": "^1.0.0",
+ "isobject": "^3.0.1",
+ "mixin-deep": "^1.2.0",
+ "pascalcase": "^0.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/base/node_modules/define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "dev": true,
+ "dependencies": {
+ "is-descriptor": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/base/node_modules/is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/base/node_modules/is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/base/node_modules/is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "dependencies": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/base/node_modules/isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/base/node_modules/kind-of": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/bcrypt-pbkdf": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+ "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
+ "dev": true,
+ "dependencies": {
+ "tweetnacl": "^0.14.3"
+ }
+ },
+ "node_modules/binary-extensions": {
+ "version": "1.13.1",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
+ "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/bindings": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
+ "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "file-uri-to-path": "1.0.0"
+ }
+ },
+ "node_modules/bluebird": {
+ "version": "3.7.2",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
+ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
+ "dev": true
+ },
+ "node_modules/body": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/body/-/body-5.1.0.tgz",
+ "integrity": "sha1-5LoM5BCkaTYyM2dgnstOZVMSUGk=",
+ "dev": true,
+ "dependencies": {
+ "continuable-cache": "^0.3.1",
+ "error": "^7.0.0",
+ "raw-body": "~1.1.0",
+ "safe-json-parse": "~1.0.1"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
+ "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "expand-range": "^1.8.1",
+ "preserve": "^0.2.0",
+ "repeat-element": "^1.1.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/browser-stdout": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
+ "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
+ "dev": true
+ },
+ "node_modules/browserslist": {
+ "version": "4.14.7",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.14.7.tgz",
+ "integrity": "sha512-BSVRLCeG3Xt/j/1cCGj1019Wbty0H+Yvu2AOuZSuoaUWn3RatbL33Cxk+Q4jRMRAbOm0p7SLravLjpnT6s0vzQ==",
+ "dev": true,
+ "dependencies": {
+ "caniuse-lite": "^1.0.30001157",
+ "colorette": "^1.2.1",
+ "electron-to-chromium": "^1.3.591",
+ "escalade": "^3.1.1",
+ "node-releases": "^1.1.66"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/bytes": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz",
+ "integrity": "sha1-NWnt6Lo0MV+rmcPpLLBMciDeH6g=",
+ "dev": true
+ },
+ "node_modules/cache-base": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
+ "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
+ "dev": true,
+ "dependencies": {
+ "collection-visit": "^1.0.0",
+ "component-emitter": "^1.2.1",
+ "get-value": "^2.0.6",
+ "has-value": "^1.0.0",
+ "isobject": "^3.0.1",
+ "set-value": "^2.0.0",
+ "to-object-path": "^0.3.0",
+ "union-value": "^1.0.0",
+ "unset-value": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/cache-base/node_modules/isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/call-bind": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz",
+ "integrity": "sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==",
+ "dev": true,
+ "dependencies": {
+ "function-bind": "^1.1.1",
+ "get-intrinsic": "^1.0.0"
+ }
+ },
+ "node_modules/call-me-maybe": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz",
+ "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=",
+ "dev": true
+ },
+ "node_modules/caller-callsite": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz",
+ "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=",
+ "dev": true,
+ "dependencies": {
+ "callsites": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/caller-callsite/node_modules/callsites": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
+ "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/caller-path": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz",
+ "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=",
+ "dev": true,
+ "dependencies": {
+ "caller-callsite": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/camelcase": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
+ "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/camelcase-keys": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
+ "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
+ "dev": true,
+ "dependencies": {
+ "camelcase": "^2.0.0",
+ "map-obj": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001157",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001157.tgz",
+ "integrity": "sha512-gOerH9Wz2IRZ2ZPdMfBvyOi3cjaz4O4dgNwPGzx8EhqAs4+2IL/O+fJsbt+znSigujoZG8bVcIAUM/I/E5K3MA==",
+ "dev": true
+ },
+ "node_modules/caseless": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
+ "dev": true
+ },
+ "node_modules/ccount": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.1.0.tgz",
+ "integrity": "sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==",
+ "dev": true
+ },
+ "node_modules/chai": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz",
+ "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==",
+ "dev": true,
+ "dependencies": {
+ "assertion-error": "^1.1.0",
+ "check-error": "^1.0.2",
+ "deep-eql": "^3.0.1",
+ "get-func-name": "^2.0.0",
+ "pathval": "^1.1.0",
+ "type-detect": "^4.0.5"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/chai-as-promised": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz",
+ "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==",
+ "dev": true,
+ "dependencies": {
+ "check-error": "^1.0.2"
+ }
+ },
+ "node_modules/chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/character-entities": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz",
+ "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==",
+ "dev": true
+ },
+ "node_modules/character-entities-html4": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.4.tgz",
+ "integrity": "sha512-HRcDxZuZqMx3/a+qrzxdBKBPUpxWEq9xw2OPZ3a/174ihfrQKVsFhqtthBInFy1zZ9GgZyFXOatNujm8M+El3g==",
+ "dev": true
+ },
+ "node_modules/character-entities-legacy": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz",
+ "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==",
+ "dev": true
+ },
+ "node_modules/character-reference-invalid": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz",
+ "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==",
+ "dev": true
+ },
+ "node_modules/chardet": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
+ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
+ "dev": true
+ },
+ "node_modules/check-error": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
+ "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz",
+ "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "anymatch": "^1.3.0",
+ "async-each": "^1.0.0",
+ "fsevents": "^1.0.0",
+ "glob-parent": "^2.0.0",
+ "inherits": "^2.0.1",
+ "is-binary-path": "^1.0.0",
+ "is-glob": "^2.0.0",
+ "path-is-absolute": "^1.0.0",
+ "readdirp": "^2.0.0"
+ }
+ },
+ "node_modules/chownr": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
+ "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/cjk-regex": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/cjk-regex/-/cjk-regex-1.0.2.tgz",
+ "integrity": "sha512-NwSMtwULPLk8Ka9DEUcoFXhMRnV/bpyKDnoyDiVw/Qy5przhvHTvXLcsKaOmx13o8J4XEsPVT1baoCUj5zQs3w==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/class-utils": {
+ "version": "0.3.6",
+ "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
+ "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
+ "dev": true,
+ "dependencies": {
+ "arr-union": "^3.1.0",
+ "define-property": "^0.2.5",
+ "isobject": "^3.0.0",
+ "static-extend": "^0.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/class-utils/node_modules/define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "dependencies": {
+ "is-descriptor": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/class-utils/node_modules/isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/clean-css": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz",
+ "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==",
+ "dev": true,
+ "dependencies": {
+ "source-map": "~0.6.0"
+ },
+ "engines": {
+ "node": ">= 4.0"
+ }
+ },
+ "node_modules/cli": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz",
+ "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=",
+ "dev": true,
+ "dependencies": {
+ "exit": "0.1.2",
+ "glob": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=0.2.5"
+ }
+ },
+ "node_modules/cli-cursor": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
+ "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
+ "dev": true,
+ "dependencies": {
+ "restore-cursor": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/cli-width": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz",
+ "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==",
+ "dev": true
+ },
+ "node_modules/cliui": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz",
+ "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==",
+ "dev": true,
+ "dependencies": {
+ "string-width": "^2.1.1",
+ "strip-ansi": "^4.0.0",
+ "wrap-ansi": "^2.0.0"
+ }
+ },
+ "node_modules/cliui/node_modules/ansi-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/cliui/node_modules/strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/clone-regexp": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/clone-regexp/-/clone-regexp-2.2.0.tgz",
+ "integrity": "sha512-beMpP7BOtTipFuW8hrJvREQ2DrRu3BE7by0ZpibtfBA+qfHYvMGTc2Yb1JMYPKg/JUw0CHYvpg796aNTSW9z7Q==",
+ "dev": true,
+ "dependencies": {
+ "is-regexp": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/code-point-at": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/coffeescript": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-1.10.0.tgz",
+ "integrity": "sha1-56qDAZF+9iGzXYo580jc3R234z4=",
+ "dev": true,
+ "bin": {
+ "cake": "bin/cake",
+ "coffee": "bin/coffee"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/collapse-white-space": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz",
+ "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==",
+ "dev": true
+ },
+ "node_modules/collection-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
+ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
+ "dev": true,
+ "dependencies": {
+ "map-visit": "^1.0.0",
+ "object-visit": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+ "dev": true
+ },
+ "node_modules/colorette": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz",
+ "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==",
+ "dev": true
+ },
+ "node_modules/colors": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
+ "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.1.90"
+ }
+ },
+ "node_modules/combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "dev": true,
+ "dependencies": {
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "dev": true
+ },
+ "node_modules/component-emitter": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
+ "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
+ "dev": true
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+ "dev": true
+ },
+ "node_modules/config": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/config/-/config-3.2.2.tgz",
+ "integrity": "sha512-rOsfIOAcG82AWouK4/vBS/OKz3UPl2T/kP0irExmXJJOoWg2CmdfPLdx56bCoMUMFNh+7soQkQWCUC8DyemiwQ==",
+ "dev": true,
+ "dependencies": {
+ "json5": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6.0.0"
+ }
+ },
+ "node_modules/config/node_modules/json5": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
+ "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
+ "dev": true,
+ "dependencies": {
+ "minimist": "^1.2.0"
+ },
+ "bin": {
+ "json5": "lib/cli.js"
+ }
+ },
+ "node_modules/console-browserify": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz",
+ "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=",
+ "dev": true,
+ "dependencies": {
+ "date-now": "^0.1.4"
+ }
+ },
+ "node_modules/console-control-strings": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
+ "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
+ "dev": true
+ },
+ "node_modules/continuable-cache": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz",
+ "integrity": "sha1-vXJ6f67XfnH/OYWskzUakSczrQ8=",
+ "dev": true
+ },
+ "node_modules/convert-source-map": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz",
+ "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "~5.1.1"
+ }
+ },
+ "node_modules/copy-descriptor": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
+ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/core-js": {
+ "version": "2.6.11",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz",
+ "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==",
+ "dev": true,
+ "hasInstallScript": true
+ },
+ "node_modules/core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+ "dev": true
+ },
+ "node_modules/cosmiconfig": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-3.1.0.tgz",
+ "integrity": "sha512-zedsBhLSbPBms+kE7AH4vHg6JsKDz6epSv2/+5XHs8ILHlgDciSJfSWf8sX9aQ52Jb7KI7VswUTsLpR/G0cr2Q==",
+ "dev": true,
+ "dependencies": {
+ "is-directory": "^0.3.1",
+ "js-yaml": "^3.9.0",
+ "parse-json": "^3.0.0",
+ "require-from-string": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/cosmiconfig/node_modules/parse-json": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-3.0.0.tgz",
+ "integrity": "sha1-+m9HsY4jgm6tMvJj50TQ4ehH+xM=",
+ "dev": true,
+ "dependencies": {
+ "error-ex": "^1.3.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/cross-env": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-5.2.0.tgz",
+ "integrity": "sha512-jtdNFfFW1hB7sMhr/H6rW1Z45LFqyI431m3qU6bFXcQ3Eh7LtBuG3h74o7ohHZ3crrRkkqHlo4jYHFPcjroANg==",
+ "dev": true,
+ "dependencies": {
+ "cross-spawn": "^6.0.5",
+ "is-windows": "^1.0.0"
+ },
+ "bin": {
+ "cross-env": "dist/bin/cross-env.js",
+ "cross-env-shell": "dist/bin/cross-env-shell.js"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/cross-spawn": {
+ "version": "6.0.5",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+ "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+ "dev": true,
+ "dependencies": {
+ "nice-try": "^1.0.4",
+ "path-key": "^2.0.1",
+ "semver": "^5.5.0",
+ "shebang-command": "^1.2.0",
+ "which": "^1.2.9"
+ },
+ "engines": {
+ "node": ">=4.8"
+ }
+ },
+ "node_modules/cssesc": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+ "dev": true,
+ "bin": {
+ "cssesc": "bin/cssesc"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/currently-unhandled": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
+ "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",
+ "dev": true,
+ "dependencies": {
+ "array-find-index": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/dashdash": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+ "dev": true,
+ "dependencies": {
+ "assert-plus": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/dashify": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/dashify/-/dashify-0.2.2.tgz",
+ "integrity": "sha1-agdBWgHJH69KMuONnfunH2HLIP4=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/date-now": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz",
+ "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=",
+ "dev": true
+ },
+ "node_modules/dateformat": {
+ "version": "1.0.12",
+ "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz",
+ "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=",
+ "dev": true,
+ "dependencies": {
+ "get-stdin": "^4.0.1",
+ "meow": "^3.3.0"
+ },
+ "bin": {
+ "dateformat": "bin/cli.js"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/decamelize-keys": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz",
+ "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=",
+ "dev": true,
+ "dependencies": {
+ "decamelize": "^1.1.0",
+ "map-obj": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/decode-uri-component": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
+ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/deep-eql": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz",
+ "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==",
+ "dev": true,
+ "dependencies": {
+ "type-detect": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/deep-is": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
+ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
+ "dev": true
+ },
+ "node_modules/default-require-extensions": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-1.0.0.tgz",
+ "integrity": "sha1-836hXT4T/9m0N9M+GnW1+5eHTLg=",
+ "dev": true,
+ "dependencies": {
+ "strip-bom": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/define-properties": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
+ "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
+ "dev": true,
+ "dependencies": {
+ "object-keys": "^1.0.12"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/define-property": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+ "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+ "dev": true,
+ "dependencies": {
+ "is-descriptor": "^1.0.2",
+ "isobject": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/define-property/node_modules/is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/define-property/node_modules/is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/define-property/node_modules/is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "dependencies": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/define-property/node_modules/isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/define-property/node_modules/kind-of": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/delegates": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+ "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
+ "dev": true
+ },
+ "node_modules/detect-indent": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz",
+ "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=",
+ "dev": true,
+ "dependencies": {
+ "repeating": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/detect-newline": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz",
+ "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/diff": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
+ "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
+ "node_modules/dir-glob": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz",
+ "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==",
+ "dev": true,
+ "dependencies": {
+ "path-type": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/dir-glob/node_modules/path-type": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
+ "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
+ "dev": true,
+ "dependencies": {
+ "pify": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/dir-glob/node_modules/pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/doctrine": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "dev": true,
+ "dependencies": {
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/dom-serializer": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
+ "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==",
+ "dev": true,
+ "dependencies": {
+ "domelementtype": "^2.0.1",
+ "entities": "^2.0.0"
+ }
+ },
+ "node_modules/dom-serializer/node_modules/domelementtype": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.2.tgz",
+ "integrity": "sha512-wFwTwCVebUrMgGeAwRL/NhZtHAUyT9n9yg4IMDwf10+6iCMxSkVq9MGCVEH+QZWo1nNidy8kNvwmv4zWHDTqvA==",
+ "dev": true
+ },
+ "node_modules/dom-serializer/node_modules/entities": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
+ "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
+ "dev": true
+ },
+ "node_modules/domelementtype": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
+ "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==",
+ "dev": true
+ },
+ "node_modules/domhandler": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz",
+ "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=",
+ "dev": true,
+ "dependencies": {
+ "domelementtype": "1"
+ }
+ },
+ "node_modules/domutils": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
+ "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=",
+ "dev": true,
+ "dependencies": {
+ "dom-serializer": "0",
+ "domelementtype": "1"
+ }
+ },
+ "node_modules/dot-prop": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
+ "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==",
+ "dev": true,
+ "dependencies": {
+ "is-obj": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/duplexer": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
+ "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
+ "dev": true
+ },
+ "node_modules/ecc-jsbn": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+ "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
+ "dev": true,
+ "dependencies": {
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.1.0"
+ }
+ },
+ "node_modules/editorconfig": {
+ "version": "0.14.2",
+ "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.14.2.tgz",
+ "integrity": "sha512-tghjvKwo1gakrhFiZWlbo5ILWAfnuOu1JFztW0li+vzbnInN0CMZuF4F0T/Pnn9UWpT7Mr1aFTWdHVuxiR9K9A==",
+ "dev": true,
+ "dependencies": {
+ "bluebird": "^3.0.5",
+ "commander": "^2.9.0",
+ "lru-cache": "^3.2.0",
+ "semver": "^5.1.0",
+ "sigmund": "^1.0.1"
+ },
+ "bin": {
+ "editorconfig": "bin/editorconfig"
+ }
+ },
+ "node_modules/editorconfig-to-prettier": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/editorconfig-to-prettier/-/editorconfig-to-prettier-0.0.6.tgz",
+ "integrity": "sha512-Ysw+hBdwhPFruYmLapKRm7Or5XgMzhasbqu4AN07V2l/AkqpgooWm2xtTQPzTD6S0tq54A+WbSxNt6qmsO3hoA==",
+ "dev": true
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.3.592",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.592.tgz",
+ "integrity": "sha512-kGNowksvqQiPb1pUSQKpd8JFoGPLxYOwduNRCqCxGh/2Q1qE2JdmwouCW41lUzDxOb/2RIV4lR0tVIfboWlO9A==",
+ "dev": true
+ },
+ "node_modules/emoji-regex": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
+ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
+ "dev": true
+ },
+ "node_modules/encoding": {
+ "version": "0.1.13",
+ "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
+ "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
+ "dev": true,
+ "dependencies": {
+ "iconv-lite": "^0.6.2"
+ }
+ },
+ "node_modules/encoding/node_modules/iconv-lite": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz",
+ "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==",
+ "dev": true,
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/end-of-stream": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+ "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+ "dev": true,
+ "dependencies": {
+ "once": "^1.4.0"
+ }
+ },
+ "node_modules/entities": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz",
+ "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=",
+ "dev": true
+ },
+ "node_modules/env-paths": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz",
+ "integrity": "sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/error": {
+ "version": "7.2.1",
+ "resolved": "https://registry.npmjs.org/error/-/error-7.2.1.tgz",
+ "integrity": "sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA==",
+ "dev": true,
+ "dependencies": {
+ "string-template": "~0.2.1"
+ }
+ },
+ "node_modules/error-ex": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+ "dev": true,
+ "dependencies": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
+ "node_modules/es-abstract": {
+ "version": "1.17.7",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
+ "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
+ "dev": true,
+ "dependencies": {
+ "es-to-primitive": "^1.2.1",
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1",
+ "is-callable": "^1.2.2",
+ "is-regex": "^1.1.1",
+ "object-inspect": "^1.8.0",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.1",
+ "string.prototype.trimend": "^1.0.1",
+ "string.prototype.trimstart": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-abstract/node_modules/object.assign": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
+ "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3",
+ "has-symbols": "^1.0.1",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-to-primitive": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
+ "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
+ "dev": true,
+ "dependencies": {
+ "is-callable": "^1.1.4",
+ "is-date-object": "^1.0.1",
+ "is-symbol": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/eslint": {
+ "version": "6.5.1",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.5.1.tgz",
+ "integrity": "sha512-32h99BoLYStT1iq1v2P9uwpyznQ4M2jRiFB6acitKz52Gqn+vPaMDUTB1bYi1WN4Nquj2w+t+bimYUG83DC55A==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.0.0",
+ "ajv": "^6.10.0",
+ "chalk": "^2.1.0",
+ "cross-spawn": "^6.0.5",
+ "debug": "^4.0.1",
+ "doctrine": "^3.0.0",
+ "eslint-scope": "^5.0.0",
+ "eslint-utils": "^1.4.2",
+ "eslint-visitor-keys": "^1.1.0",
+ "espree": "^6.1.1",
+ "esquery": "^1.0.1",
+ "esutils": "^2.0.2",
+ "file-entry-cache": "^5.0.1",
+ "functional-red-black-tree": "^1.0.1",
+ "glob-parent": "^5.0.0",
+ "globals": "^11.7.0",
+ "ignore": "^4.0.6",
+ "import-fresh": "^3.0.0",
+ "imurmurhash": "^0.1.4",
+ "inquirer": "^6.4.1",
+ "is-glob": "^4.0.0",
+ "js-yaml": "^3.13.1",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.3.0",
+ "lodash": "^4.17.14",
+ "minimatch": "^3.0.4",
+ "mkdirp": "^0.5.1",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.8.2",
+ "progress": "^2.0.0",
+ "regexpp": "^2.0.1",
+ "semver": "^6.1.2",
+ "strip-ansi": "^5.2.0",
+ "strip-json-comments": "^3.0.1",
+ "table": "^5.2.3",
+ "text-table": "^0.2.0",
+ "v8-compile-cache": "^2.0.3"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
+ },
+ "engines": {
+ "node": "^8.10.0 || ^10.13.0 || >=11.10.1"
+ }
+ },
+ "node_modules/eslint-config-wpcalypso": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/eslint-config-wpcalypso/-/eslint-config-wpcalypso-4.0.1.tgz",
+ "integrity": "sha512-/MdCPOQusYRJI57/GFNi523CW75CUIoqKEY+8XhDtkz0iSeFXl12c2hW2l4ezE0cDbhMUwSslI07YpSPW7nRgA==",
+ "dev": true
+ },
+ "node_modules/eslint-plugin-wpcalypso": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-wpcalypso/-/eslint-plugin-wpcalypso-4.1.0.tgz",
+ "integrity": "sha512-2gZdaaX5rS7vve5FfIBTANPFXfQstxMppUFR8KzrY5cJPt7hIhpg9lOb4y0hVYNdJkhZxkvEWw8yoJhaUc1OYQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/eslint-scope": {
+ "version": "3.7.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz",
+ "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=",
+ "dev": true,
+ "dependencies": {
+ "esrecurse": "^4.1.0",
+ "estraverse": "^4.1.1"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/eslint-utils": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz",
+ "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==",
+ "dev": true,
+ "dependencies": {
+ "eslint-visitor-keys": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/eslint-visitor-keys": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
+ "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/eslint/node_modules/ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/eslint/node_modules/debug": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz",
+ "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ }
+ },
+ "node_modules/eslint/node_modules/eslint-scope": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+ "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+ "dev": true,
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^4.1.1"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/eslint/node_modules/glob-parent": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
+ "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
+ "dev": true,
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/eslint/node_modules/globals": {
+ "version": "11.12.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/eslint/node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/eslint/node_modules/is-glob": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
+ "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
+ "dev": true,
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/eslint/node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "node_modules/eslint/node_modules/semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/eslint/node_modules/strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/espree": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz",
+ "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==",
+ "dev": true,
+ "dependencies": {
+ "acorn": "^7.1.1",
+ "acorn-jsx": "^5.2.0",
+ "eslint-visitor-keys": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "dev": true,
+ "bin": {
+ "esparse": "bin/esparse.js",
+ "esvalidate": "bin/esvalidate.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/esquery": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz",
+ "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==",
+ "dev": true,
+ "dependencies": {
+ "estraverse": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/esquery/node_modules/estraverse": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
+ "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "dev": true,
+ "dependencies": {
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esrecurse/node_modules/estraverse": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
+ "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estraverse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/eventemitter2": {
+ "version": "0.4.14",
+ "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz",
+ "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=",
+ "dev": true
+ },
+ "node_modules/execa": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
+ "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
+ "dev": true,
+ "dependencies": {
+ "cross-spawn": "^6.0.0",
+ "get-stream": "^4.0.0",
+ "is-stream": "^1.1.0",
+ "npm-run-path": "^2.0.0",
+ "p-finally": "^1.0.0",
+ "signal-exit": "^3.0.0",
+ "strip-eof": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/execall": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/execall/-/execall-2.0.0.tgz",
+ "integrity": "sha512-0FU2hZ5Hh6iQnarpRtQurM/aAvp3RIbfvgLHrcqJYzhXyV2KFruhuChf9NC6waAhiUR7FFtlugkI4p7f2Fqlow==",
+ "dev": true,
+ "dependencies": {
+ "clone-regexp": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/exit": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
+ "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/exit-hook": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz",
+ "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/expand-brackets": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
+ "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-posix-bracket": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/expand-range": {
+ "version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
+ "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "fill-range": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+ "dev": true
+ },
+ "node_modules/extend-shallow": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
+ "dev": true,
+ "dependencies": {
+ "assign-symbols": "^1.0.0",
+ "is-extendable": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/extend-shallow/node_modules/is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+ "dev": true,
+ "dependencies": {
+ "is-plain-object": "^2.0.4"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/external-editor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
+ "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
+ "dev": true,
+ "dependencies": {
+ "chardet": "^0.7.0",
+ "iconv-lite": "^0.4.24",
+ "tmp": "^0.0.33"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/extglob": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
+ "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-extglob": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/extsprintf": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
+ "dev": true,
+ "engines": [
+ "node >=0.6.0"
+ ]
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true
+ },
+ "node_modules/fast-glob": {
+ "version": "2.2.7",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz",
+ "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==",
+ "dev": true,
+ "dependencies": {
+ "@mrmlnc/readdir-enhanced": "^2.2.1",
+ "@nodelib/fs.stat": "^1.1.2",
+ "glob-parent": "^3.1.0",
+ "is-glob": "^4.0.0",
+ "merge2": "^1.2.3",
+ "micromatch": "^3.1.10"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/arr-diff": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+ "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/array-unique": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/braces": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+ "dev": true,
+ "dependencies": {
+ "arr-flatten": "^1.1.0",
+ "array-unique": "^0.3.2",
+ "extend-shallow": "^2.0.1",
+ "fill-range": "^4.0.0",
+ "isobject": "^3.0.1",
+ "repeat-element": "^1.1.2",
+ "snapdragon": "^0.8.1",
+ "snapdragon-node": "^2.0.1",
+ "split-string": "^3.0.2",
+ "to-regex": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/braces/node_modules/extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "dependencies": {
+ "is-extendable": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/expand-brackets": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
+ "dev": true,
+ "dependencies": {
+ "debug": "^2.3.3",
+ "define-property": "^0.2.5",
+ "extend-shallow": "^2.0.1",
+ "posix-character-classes": "^0.1.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/expand-brackets/node_modules/define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "dependencies": {
+ "is-descriptor": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/expand-brackets/node_modules/extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "dependencies": {
+ "is-extendable": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/expand-brackets/node_modules/is-accessor-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/expand-brackets/node_modules/is-accessor-descriptor/node_modules/kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "dependencies": {
+ "is-buffer": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/expand-brackets/node_modules/is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/expand-brackets/node_modules/is-data-descriptor/node_modules/kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "dependencies": {
+ "is-buffer": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/expand-brackets/node_modules/is-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+ "dev": true,
+ "dependencies": {
+ "is-accessor-descriptor": "^0.1.6",
+ "is-data-descriptor": "^0.1.4",
+ "kind-of": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/expand-brackets/node_modules/kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/extglob": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+ "dev": true,
+ "dependencies": {
+ "array-unique": "^0.3.2",
+ "define-property": "^1.0.0",
+ "expand-brackets": "^2.1.4",
+ "extend-shallow": "^2.0.1",
+ "fragment-cache": "^0.2.1",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/extglob/node_modules/define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "dev": true,
+ "dependencies": {
+ "is-descriptor": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/extglob/node_modules/extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "dependencies": {
+ "is-extendable": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/fill-range": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+ "dev": true,
+ "dependencies": {
+ "extend-shallow": "^2.0.1",
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1",
+ "to-regex-range": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/fill-range/node_modules/extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "dependencies": {
+ "is-extendable": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/glob-parent": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
+ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
+ "dev": true,
+ "dependencies": {
+ "is-glob": "^3.1.0",
+ "path-dirname": "^1.0.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/glob-parent/node_modules/is-glob": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+ "dev": true,
+ "dependencies": {
+ "is-extglob": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "dependencies": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/is-glob": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
+ "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
+ "dev": true,
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/is-number/node_modules/kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "dependencies": {
+ "is-buffer": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/kind-of": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/micromatch": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+ "dev": true,
+ "dependencies": {
+ "arr-diff": "^4.0.0",
+ "array-unique": "^0.3.2",
+ "braces": "^2.3.1",
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "extglob": "^2.0.4",
+ "fragment-cache": "^0.2.1",
+ "kind-of": "^6.0.2",
+ "nanomatch": "^1.2.9",
+ "object.pick": "^1.3.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true
+ },
+ "node_modules/fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
+ "dev": true
+ },
+ "node_modules/fault": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz",
+ "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==",
+ "dev": true,
+ "dependencies": {
+ "format": "^0.2.0"
+ }
+ },
+ "node_modules/faye-websocket": {
+ "version": "0.10.0",
+ "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz",
+ "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=",
+ "dev": true,
+ "dependencies": {
+ "websocket-driver": ">=0.5.1"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/figures": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
+ "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
+ "dev": true,
+ "dependencies": {
+ "escape-string-regexp": "^1.0.5"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/file-entry-cache": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz",
+ "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==",
+ "dev": true,
+ "dependencies": {
+ "flat-cache": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/file-sync-cmp": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/file-sync-cmp/-/file-sync-cmp-0.1.1.tgz",
+ "integrity": "sha1-peeo/7+kk7Q7kju9TKiaU7Y7YSs=",
+ "dev": true
+ },
+ "node_modules/file-uri-to-path": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
+ "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
+ "dev": true,
+ "optional": true
+ },
+ "node_modules/filename-regex": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
+ "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=",
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fileset": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz",
+ "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=",
+ "dev": true,
+ "dependencies": {
+ "glob": "^7.0.3",
+ "minimatch": "^3.0.3"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz",
+ "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-number": "^2.1.0",
+ "isobject": "^2.0.0",
+ "randomatic": "^3.0.0",
+ "repeat-element": "^1.1.2",
+ "repeat-string": "^1.5.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/find-up": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
+ "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
+ "dev": true,
+ "dependencies": {
+ "path-exists": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/findup-sync": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz",
+ "integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=",
+ "dev": true,
+ "dependencies": {
+ "glob": "~5.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6.0"
+ }
+ },
+ "node_modules/findup-sync/node_modules/glob": {
+ "version": "5.0.15",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
+ "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=",
+ "dev": true,
+ "dependencies": {
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "2 || 3",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/flat": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.1.tgz",
+ "integrity": "sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA==",
+ "dev": true,
+ "dependencies": {
+ "is-buffer": "~2.0.3"
+ },
+ "bin": {
+ "flat": "cli.js"
+ }
+ },
+ "node_modules/flat-cache": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz",
+ "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==",
+ "dev": true,
+ "dependencies": {
+ "flatted": "^2.0.0",
+ "rimraf": "2.6.3",
+ "write": "1.0.3"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/flat/node_modules/is-buffer": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
+ "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/flatted": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz",
+ "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==",
+ "dev": true
+ },
+ "node_modules/flatten": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.3.tgz",
+ "integrity": "sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==",
+ "dev": true
+ },
+ "node_modules/flow-parser": {
+ "version": "0.59.0",
+ "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.59.0.tgz",
+ "integrity": "sha1-9uvK5h/6GH5CCZnUDOCoAfObJjU=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/for-in": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/for-own": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz",
+ "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "for-in": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/forever-agent": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+ "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/form-data": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
+ "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
+ "dev": true,
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.6",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 0.12"
+ }
+ },
+ "node_modules/format": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz",
+ "integrity": "sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4.x"
+ }
+ },
+ "node_modules/fragment-cache": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
+ "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
+ "dev": true,
+ "dependencies": {
+ "map-cache": "^0.2.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fs-minipass": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
+ "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
+ "dev": true,
+ "dependencies": {
+ "minipass": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/fs-readdir-recursive": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz",
+ "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==",
+ "dev": true
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+ "dev": true
+ },
+ "node_modules/fsevents": {
+ "version": "1.2.13",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
+ "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "dependencies": {
+ "bindings": "^1.5.0",
+ "nan": "^2.12.1"
+ },
+ "engines": {
+ "node": ">= 4.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+ "dev": true
+ },
+ "node_modules/functional-red-black-tree": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
+ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
+ "dev": true
+ },
+ "node_modules/gauge": {
+ "version": "2.7.4",
+ "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
+ "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
+ "dev": true,
+ "dependencies": {
+ "aproba": "^1.0.3",
+ "console-control-strings": "^1.0.0",
+ "has-unicode": "^2.0.0",
+ "object-assign": "^4.1.0",
+ "signal-exit": "^3.0.0",
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1",
+ "wide-align": "^1.1.0"
+ }
+ },
+ "node_modules/gauge/node_modules/is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+ "dev": true,
+ "dependencies": {
+ "number-is-nan": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/gauge/node_modules/string-width": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+ "dev": true,
+ "dependencies": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/gaze": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz",
+ "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==",
+ "dev": true,
+ "dependencies": {
+ "globule": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
+ "node_modules/gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "dev": true,
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
+ },
+ "node_modules/get-func-name": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
+ "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.1.tgz",
+ "integrity": "sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg==",
+ "dev": true,
+ "dependencies": {
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1"
+ }
+ },
+ "node_modules/get-stdin": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
+ "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/get-stream": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
+ "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
+ "dev": true,
+ "dependencies": {
+ "pump": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/get-value": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+ "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/getobject": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz",
+ "integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/getpass": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+ "dev": true,
+ "dependencies": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "node_modules/gettext-parser": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/gettext-parser/-/gettext-parser-3.1.1.tgz",
+ "integrity": "sha512-vNhWcqXEtZPs5Ft1ReA34g7ByWotpcOIeJvXVy2jF3/G2U9v6W0wG4Z4hXzcU8R//jArqkgHcVCGgGqa4vxVlQ==",
+ "dev": true,
+ "dependencies": {
+ "encoding": "^0.1.12",
+ "readable-stream": "^3.2.0",
+ "safe-buffer": "^5.1.2"
+ }
+ },
+ "node_modules/gettext-parser/node_modules/readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "dev": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/glob-base": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
+ "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "glob-parent": "^2.0.0",
+ "is-glob": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
+ "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-glob": "^2.0.0"
+ }
+ },
+ "node_modules/glob-to-regexp": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz",
+ "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=",
+ "dev": true
+ },
+ "node_modules/global-modules": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz",
+ "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==",
+ "dev": true,
+ "dependencies": {
+ "global-prefix": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/global-prefix": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz",
+ "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==",
+ "dev": true,
+ "dependencies": {
+ "ini": "^1.3.5",
+ "kind-of": "^6.0.2",
+ "which": "^1.3.1"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/global-prefix/node_modules/kind-of": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/globals": {
+ "version": "9.18.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
+ "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/globby": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
+ "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=",
+ "dev": true,
+ "dependencies": {
+ "array-union": "^1.0.1",
+ "glob": "^7.0.3",
+ "object-assign": "^4.0.1",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/globjoin": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz",
+ "integrity": "sha1-L0SUrIkZ43Z8XLtpHp9GMyQoXUM=",
+ "dev": true
+ },
+ "node_modules/globule": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.2.tgz",
+ "integrity": "sha512-7IDTQTIu2xzXkT+6mlluidnWo+BypnbSoEVVQCGfzqnl5Ik8d3e1d4wycb8Rj9tWW+Z39uPWsdlquqiqPCd/pA==",
+ "dev": true,
+ "dependencies": {
+ "glob": "~7.1.1",
+ "lodash": "~4.17.10",
+ "minimatch": "~3.0.2"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/gonzales-pe": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/gonzales-pe/-/gonzales-pe-4.3.0.tgz",
+ "integrity": "sha512-otgSPpUmdWJ43VXyiNgEYE4luzHCL2pz4wQ0OnDluC6Eg4Ko3Vexy/SrSynglw/eR+OhkzmqFCZa/OFa/RgAOQ==",
+ "dev": true,
+ "dependencies": {
+ "minimist": "^1.2.5"
+ },
+ "bin": {
+ "gonzales": "bin/gonzales.js"
+ },
+ "engines": {
+ "node": ">=0.6.0"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
+ "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
+ "dev": true
+ },
+ "node_modules/graphql": {
+ "version": "0.10.5",
+ "resolved": "https://registry.npmjs.org/graphql/-/graphql-0.10.5.tgz",
+ "integrity": "sha512-Q7cx22DiLhwHsEfUnUip1Ww/Vfx7FS0w6+iHItNuN61+XpegHSa3k5U0+6M5BcpavQImBwFiy0z3uYwY7cXMLQ==",
+ "dev": true,
+ "dependencies": {
+ "iterall": "^1.1.0"
+ }
+ },
+ "node_modules/growl": {
+ "version": "1.10.5",
+ "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
+ "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.x"
+ }
+ },
+ "node_modules/grunt": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.0.4.tgz",
+ "integrity": "sha512-PYsMOrOC+MsdGEkFVwMaMyc6Ob7pKmq+deg1Sjr+vvMWp35sztfwKE7qoN51V+UEtHsyNuMcGdgMLFkBHvMxHQ==",
+ "dev": true,
+ "dependencies": {
+ "coffeescript": "~1.10.0",
+ "dateformat": "~1.0.12",
+ "eventemitter2": "~0.4.13",
+ "exit": "~0.1.1",
+ "findup-sync": "~0.3.0",
+ "glob": "~7.0.0",
+ "grunt-cli": "~1.2.0",
+ "grunt-known-options": "~1.1.0",
+ "grunt-legacy-log": "~2.0.0",
+ "grunt-legacy-util": "~1.1.1",
+ "iconv-lite": "~0.4.13",
+ "js-yaml": "~3.13.0",
+ "minimatch": "~3.0.2",
+ "mkdirp": "~0.5.1",
+ "nopt": "~3.0.6",
+ "path-is-absolute": "~1.0.0",
+ "rimraf": "~2.6.2"
+ },
+ "bin": {
+ "grunt": "bin/grunt"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/grunt-checktextdomain": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/grunt-checktextdomain/-/grunt-checktextdomain-1.0.1.tgz",
+ "integrity": "sha1-slTQHh3pEwBdTbHFMD2QI7mD4Zs=",
+ "dev": true,
+ "dependencies": {
+ "chalk": "~0.2.1",
+ "text-table": "~0.2.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/grunt-checktextdomain/node_modules/ansi-styles": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-0.2.0.tgz",
+ "integrity": "sha1-NZq0sV3NZLptdHNLcsNjYKmvLBk=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/grunt-checktextdomain/node_modules/chalk": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.2.1.tgz",
+ "integrity": "sha1-dhPhV1FFshOGSD9/SFql/6jL0Qw=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "~0.2.0",
+ "has-color": "~0.1.0"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/grunt-contrib-clean": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/grunt-contrib-clean/-/grunt-contrib-clean-2.0.0.tgz",
+ "integrity": "sha512-g5ZD3ORk6gMa5ugZosLDQl3dZO7cI3R14U75hTM+dVLVxdMNJCPVmwf9OUt4v4eWgpKKWWoVK9DZc1amJp4nQw==",
+ "dev": true,
+ "dependencies": {
+ "async": "^2.6.1",
+ "rimraf": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/grunt-contrib-clean/node_modules/async": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
+ "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
+ "dev": true,
+ "dependencies": {
+ "lodash": "^4.17.14"
+ }
+ },
+ "node_modules/grunt-contrib-concat": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/grunt-contrib-concat/-/grunt-contrib-concat-1.0.1.tgz",
+ "integrity": "sha1-YVCYYwhOhx1+ht5IwBUlntl3Rb0=",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.0.0",
+ "source-map": "^0.5.3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/grunt-contrib-concat/node_modules/ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/grunt-contrib-concat/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/grunt-contrib-concat/node_modules/source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/grunt-contrib-concat/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/grunt-contrib-copy": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/grunt-contrib-copy/-/grunt-contrib-copy-1.0.0.tgz",
+ "integrity": "sha1-cGDGWB6QS4qw0A8HbgqPbj58NXM=",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.1",
+ "file-sync-cmp": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/grunt-contrib-copy/node_modules/ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/grunt-contrib-copy/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/grunt-contrib-copy/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/grunt-contrib-cssmin": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/grunt-contrib-cssmin/-/grunt-contrib-cssmin-3.0.0.tgz",
+ "integrity": "sha512-eXpooYmVGKMs/xV7DzTLgJFPVOfMuawPD3x0JwhlH0mumq2NtH3xsxaHxp1Y3NKxp0j0tRhFS6kSBRsz6TuTGg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.4.1",
+ "clean-css": "~4.2.1",
+ "maxmin": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=6.0"
+ }
+ },
+ "node_modules/grunt-contrib-jshint": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/grunt-contrib-jshint/-/grunt-contrib-jshint-2.1.0.tgz",
+ "integrity": "sha512-65S2/C/6RfjY/umTxfwXXn+wVvaYmykHkHSsW6Q6rhkbv3oudTEgqnFFZvWzWCoHUb+3GMZLbP3oSrNyvshmIQ==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.4.2",
+ "hooker": "^0.2.3",
+ "jshint": "~2.10.2"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/grunt-contrib-uglify": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-4.0.1.tgz",
+ "integrity": "sha512-dwf8/+4uW1+7pH72WButOEnzErPGmtUvc8p08B0eQS/6ON0WdeQu0+WFeafaPTbbY1GqtS25lsHWaDeiTQNWPg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.4.1",
+ "maxmin": "^2.1.0",
+ "uglify-js": "^3.5.0",
+ "uri-path": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/grunt-contrib-watch": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/grunt-contrib-watch/-/grunt-contrib-watch-1.1.0.tgz",
+ "integrity": "sha512-yGweN+0DW5yM+oo58fRu/XIRrPcn3r4tQx+nL7eMRwjpvk+rQY6R8o94BPK0i2UhTg9FN21hS+m8vR8v9vXfeg==",
+ "dev": true,
+ "dependencies": {
+ "async": "^2.6.0",
+ "gaze": "^1.1.0",
+ "lodash": "^4.17.10",
+ "tiny-lr": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/grunt-contrib-watch/node_modules/async": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
+ "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
+ "dev": true,
+ "dependencies": {
+ "lodash": "^4.17.14"
+ }
+ },
+ "node_modules/grunt-known-options": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-1.1.1.tgz",
+ "integrity": "sha512-cHwsLqoighpu7TuYj5RonnEuxGVFnztcUqTqp5rXFGYL4OuPFofwC4Ycg7n9fYwvK6F5WbYgeVOwph9Crs2fsQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/grunt-legacy-log": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-2.0.0.tgz",
+ "integrity": "sha512-1m3+5QvDYfR1ltr8hjiaiNjddxGdQWcH0rw1iKKiQnF0+xtgTazirSTGu68RchPyh1OBng1bBUjLmX8q9NpoCw==",
+ "dev": true,
+ "dependencies": {
+ "colors": "~1.1.2",
+ "grunt-legacy-log-utils": "~2.0.0",
+ "hooker": "~0.2.3",
+ "lodash": "~4.17.5"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/grunt-legacy-log-utils": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-2.0.1.tgz",
+ "integrity": "sha512-o7uHyO/J+i2tXG8r2bZNlVk20vlIFJ9IEYyHMCQGfWYru8Jv3wTqKZzvV30YW9rWEjq0eP3cflQ1qWojIe9VFA==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "~2.4.1",
+ "lodash": "~4.17.10"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/grunt-legacy-util": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-1.1.1.tgz",
+ "integrity": "sha512-9zyA29w/fBe6BIfjGENndwoe1Uy31BIXxTH3s8mga0Z5Bz2Sp4UCjkeyv2tI449ymkx3x26B+46FV4fXEddl5A==",
+ "dev": true,
+ "dependencies": {
+ "async": "~1.5.2",
+ "exit": "~0.1.1",
+ "getobject": "~0.1.0",
+ "hooker": "~0.2.3",
+ "lodash": "~4.17.10",
+ "underscore.string": "~3.3.4",
+ "which": "~1.3.0"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/grunt-phpcs": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/grunt-phpcs/-/grunt-phpcs-0.4.0.tgz",
+ "integrity": "sha1-oI1iX8ZEZeRTsr2T+BCyqB6Uvao=",
+ "dev": true,
+ "engines": {
+ "node": "0.10.x"
+ }
+ },
+ "node_modules/grunt-postcss": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/grunt-postcss/-/grunt-postcss-0.9.0.tgz",
+ "integrity": "sha512-lglLcVaoOIqH0sFv7RqwUKkEFGQwnlqyAKbatxZderwZGV1nDyKHN7gZS9LUiTx1t5GOvRBx0BEalHMyVwFAIA==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.1.0",
+ "diff": "^3.0.0",
+ "postcss": "^6.0.11"
+ },
+ "engines": {
+ "node": ">= 0.12.0"
+ }
+ },
+ "node_modules/grunt-postcss/node_modules/postcss": {
+ "version": "6.0.23",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
+ "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.4.1",
+ "source-map": "^0.6.1",
+ "supports-color": "^5.4.0"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/grunt-prompt": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/grunt-prompt/-/grunt-prompt-1.3.3.tgz",
+ "integrity": "sha1-xbQ77DqimqaWKsZhGolnEvy6Z5E=",
+ "dev": true,
+ "dependencies": {
+ "inquirer": "^0.11.0",
+ "lodash": "^3.10.1"
+ }
+ },
+ "node_modules/grunt-prompt/node_modules/ansi-escapes": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz",
+ "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/grunt-prompt/node_modules/ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/grunt-prompt/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/grunt-prompt/node_modules/cli-cursor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz",
+ "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=",
+ "dev": true,
+ "dependencies": {
+ "restore-cursor": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/grunt-prompt/node_modules/cli-width": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-1.1.1.tgz",
+ "integrity": "sha1-pNKT72frt7iNSk1CwMzwDE0eNm0=",
+ "dev": true
+ },
+ "node_modules/grunt-prompt/node_modules/figures": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz",
+ "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=",
+ "dev": true,
+ "dependencies": {
+ "escape-string-regexp": "^1.0.5",
+ "object-assign": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/grunt-prompt/node_modules/inquirer": {
+ "version": "0.11.4",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.11.4.tgz",
+ "integrity": "sha1-geM3ToNhvq/y2XAWIG01nQsy+k0=",
+ "dev": true,
+ "dependencies": {
+ "ansi-escapes": "^1.1.0",
+ "ansi-regex": "^2.0.0",
+ "chalk": "^1.0.0",
+ "cli-cursor": "^1.0.1",
+ "cli-width": "^1.0.1",
+ "figures": "^1.3.5",
+ "lodash": "^3.3.1",
+ "readline2": "^1.0.1",
+ "run-async": "^0.1.0",
+ "rx-lite": "^3.1.2",
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.0",
+ "through": "^2.3.6"
+ }
+ },
+ "node_modules/grunt-prompt/node_modules/is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+ "dev": true,
+ "dependencies": {
+ "number-is-nan": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/grunt-prompt/node_modules/lodash": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
+ "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=",
+ "dev": true
+ },
+ "node_modules/grunt-prompt/node_modules/onetime": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz",
+ "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/grunt-prompt/node_modules/restore-cursor": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz",
+ "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=",
+ "dev": true,
+ "dependencies": {
+ "exit-hook": "^1.0.0",
+ "onetime": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/grunt-prompt/node_modules/run-async": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz",
+ "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=",
+ "dev": true,
+ "dependencies": {
+ "once": "^1.3.0"
+ }
+ },
+ "node_modules/grunt-prompt/node_modules/string-width": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+ "dev": true,
+ "dependencies": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/grunt-prompt/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/grunt-rtlcss": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/grunt-rtlcss/-/grunt-rtlcss-2.0.1.tgz",
+ "integrity": "sha1-6eYc5DdAY5f546Sxv2aeR+cf/MM=",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.0.0",
+ "rtlcss": "^2.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/grunt-rtlcss/node_modules/ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/grunt-rtlcss/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/grunt-rtlcss/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/grunt-sass": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/grunt-sass/-/grunt-sass-3.0.2.tgz",
+ "integrity": "sha512-Ogq4cWqBre71gZIkgxIxevgzZHSIIsrKu/5yvPDl4Mvib0A4TRTJEQUdpQ0YV1iai0DPjayz02vDJE6KUVHQ2w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/grunt-shell": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/grunt-shell/-/grunt-shell-3.0.1.tgz",
+ "integrity": "sha512-C8eR4frw/NmIFIwSvzSLS4wOQBUzC+z6QhrKPzwt/tlaIqlzH35i/O2MggVOBj2Sh1tbaAqpASWxGiGsi4JMIQ==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.4.1",
+ "npm-run-path": "^2.0.0",
+ "strip-ansi": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/grunt-shell/node_modules/ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/grunt-shell/node_modules/strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/grunt-stylelint": {
+ "version": "0.11.1",
+ "resolved": "https://registry.npmjs.org/grunt-stylelint/-/grunt-stylelint-0.11.1.tgz",
+ "integrity": "sha512-DYq74oCsk6Q/fmUarv4CGrt6M/61yrtHRSM5FfrJy8uLFo+WQ/tiMWmROk+53Vvq3GWz8+m/Rz/Ne+Ag0QZvjw==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "2.4.2"
+ }
+ },
+ "node_modules/grunt-wp-i18n": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/grunt-wp-i18n/-/grunt-wp-i18n-1.0.3.tgz",
+ "integrity": "sha512-CJNbEKeBeOSAPeaJ9B8iCgSwtaG63UR9/uT46a4OsIqnFhOJpeAi138JTlvjfIbnDVoBrzvdrKJe1svveLjUtA==",
+ "dev": true,
+ "dependencies": {
+ "grunt": "^1.0.3",
+ "node-wp-i18n": "^1.2.2"
+ },
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/grunt/node_modules/glob": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz",
+ "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=",
+ "dev": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.2",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/grunt/node_modules/grunt-cli": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.2.0.tgz",
+ "integrity": "sha1-VisRnrsGndtGSs4oRVAb6Xs1tqg=",
+ "dev": true,
+ "dependencies": {
+ "findup-sync": "~0.3.0",
+ "grunt-known-options": "~1.1.0",
+ "nopt": "~3.0.6",
+ "resolve": "~1.1.0"
+ },
+ "bin": {
+ "grunt": "bin/grunt"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/grunt/node_modules/js-yaml": {
+ "version": "3.13.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
+ "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
+ "dev": true,
+ "dependencies": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/grunt/node_modules/resolve": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",
+ "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=",
+ "dev": true
+ },
+ "node_modules/gzip-size": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-3.0.0.tgz",
+ "integrity": "sha1-VGGI6b3DN/Zzdy+BZgRks4nc5SA=",
+ "dev": true,
+ "dependencies": {
+ "duplexer": "^0.1.1"
+ },
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/handlebars": {
+ "version": "4.7.6",
+ "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz",
+ "integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==",
+ "dev": true,
+ "dependencies": {
+ "minimist": "^1.2.5",
+ "neo-async": "^2.6.0",
+ "source-map": "^0.6.1",
+ "uglify-js": "^3.1.4",
+ "wordwrap": "^1.0.0"
+ },
+ "bin": {
+ "handlebars": "bin/handlebars"
+ },
+ "engines": {
+ "node": ">=0.4.7"
+ }
+ },
+ "node_modules/har-schema": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
+ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/har-validator": {
+ "version": "5.1.5",
+ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
+ "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
+ "dev": true,
+ "dependencies": {
+ "ajv": "^6.12.3",
+ "har-schema": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "dev": true,
+ "dependencies": {
+ "function-bind": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/has-ansi": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/has-color": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz",
+ "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
+ "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/has-unicode": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
+ "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
+ "dev": true
+ },
+ "node_modules/has-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
+ "dev": true,
+ "dependencies": {
+ "get-value": "^2.0.6",
+ "has-values": "^1.0.0",
+ "isobject": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/has-value/node_modules/isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/has-values": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
+ "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
+ "dev": true,
+ "dependencies": {
+ "is-number": "^3.0.0",
+ "kind-of": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/has-values/node_modules/is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/has-values/node_modules/is-number/node_modules/kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "dependencies": {
+ "is-buffer": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/has-values/node_modules/kind-of": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
+ "dev": true,
+ "dependencies": {
+ "is-buffer": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/he": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+ "dev": true,
+ "bin": {
+ "he": "bin/he"
+ }
+ },
+ "node_modules/home-or-tmp": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
+ "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=",
+ "dev": true,
+ "dependencies": {
+ "os-homedir": "^1.0.0",
+ "os-tmpdir": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/hooker": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz",
+ "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/hosted-git-info": {
+ "version": "2.8.8",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
+ "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==",
+ "dev": true
+ },
+ "node_modules/html-tags": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz",
+ "integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/htmlparser2": {
+ "version": "3.8.3",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz",
+ "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=",
+ "dev": true,
+ "dependencies": {
+ "domelementtype": "1",
+ "domhandler": "2.3",
+ "domutils": "1.5",
+ "entities": "1.0",
+ "readable-stream": "1.1"
+ }
+ },
+ "node_modules/htmlparser2/node_modules/isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
+ "dev": true
+ },
+ "node_modules/htmlparser2/node_modules/readable-stream": {
+ "version": "1.1.14",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
+ "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
+ "dev": true,
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.1",
+ "isarray": "0.0.1",
+ "string_decoder": "~0.10.x"
+ }
+ },
+ "node_modules/htmlparser2/node_modules/string_decoder": {
+ "version": "0.10.31",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
+ "dev": true
+ },
+ "node_modules/http-parser-js": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.2.tgz",
+ "integrity": "sha512-opCO9ASqg5Wy2FNo7A0sxy71yGbbkJJXLdgMK04Tcypw9jr2MgWbyubb0+WdmDmGnFflO7fRbqbaihh/ENDlRQ==",
+ "dev": true
+ },
+ "node_modules/http-signature": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
+ "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+ "dev": true,
+ "dependencies": {
+ "assert-plus": "^1.0.0",
+ "jsprim": "^1.2.2",
+ "sshpk": "^1.7.0"
+ },
+ "engines": {
+ "node": ">=0.8",
+ "npm": ">=1.3.7"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "dev": true,
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/ignore": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
+ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/import-fresh": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.2.tgz",
+ "integrity": "sha512-cTPNrlvJT6twpYy+YmKUKrTSjWFs3bjYjAhCwm+z4EOCubZxAuO+hHpRN64TqjEaYSHs7tJAE0w1CKMGmsG/lw==",
+ "dev": true,
+ "dependencies": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/import-lazy": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz",
+ "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.19"
+ }
+ },
+ "node_modules/indent-string": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
+ "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=",
+ "dev": true,
+ "dependencies": {
+ "repeating": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/indexes-of": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz",
+ "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=",
+ "dev": true
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "dev": true,
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "node_modules/ini": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
+ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/inquirer": {
+ "version": "6.5.2",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz",
+ "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-escapes": "^3.2.0",
+ "chalk": "^2.4.2",
+ "cli-cursor": "^2.1.0",
+ "cli-width": "^2.0.0",
+ "external-editor": "^3.0.3",
+ "figures": "^2.0.0",
+ "lodash": "^4.17.12",
+ "mute-stream": "0.0.7",
+ "run-async": "^2.2.0",
+ "rxjs": "^6.4.0",
+ "string-width": "^2.1.0",
+ "strip-ansi": "^5.1.0",
+ "through": "^2.3.6"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/inquirer/node_modules/ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/inquirer/node_modules/strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/invariant": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
+ "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
+ "dev": true,
+ "dependencies": {
+ "loose-envify": "^1.0.0"
+ }
+ },
+ "node_modules/invert-kv": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz",
+ "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/is-accessor-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-alphabetical": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz",
+ "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==",
+ "dev": true
+ },
+ "node_modules/is-alphanumeric": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-alphanumeric/-/is-alphanumeric-1.0.0.tgz",
+ "integrity": "sha1-Spzvcdr0wAHB2B1j0UDPU/1oifQ=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-alphanumerical": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz",
+ "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==",
+ "dev": true,
+ "dependencies": {
+ "is-alphabetical": "^1.0.0",
+ "is-decimal": "^1.0.0"
+ }
+ },
+ "node_modules/is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
+ "dev": true
+ },
+ "node_modules/is-binary-path": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
+ "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "binary-extensions": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-buffer": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+ "dev": true
+ },
+ "node_modules/is-callable": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz",
+ "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/is-core-module": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.1.0.tgz",
+ "integrity": "sha512-YcV7BgVMRFRua2FqQzKtTDMz8iCuLEyGKjr70q8Zm1yy2qKcurbFEd79PAdHV77oL3NrAaOVQIbMmiHQCHB7ZA==",
+ "dev": true,
+ "dependencies": {
+ "has": "^1.0.3"
+ }
+ },
+ "node_modules/is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-date-object": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz",
+ "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/is-decimal": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz",
+ "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==",
+ "dev": true
+ },
+ "node_modules/is-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+ "dev": true,
+ "dependencies": {
+ "is-accessor-descriptor": "^0.1.6",
+ "is-data-descriptor": "^0.1.4",
+ "kind-of": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-descriptor/node_modules/kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-directory": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz",
+ "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-dotfile": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",
+ "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=",
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-equal-shallow": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
+ "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-primitive": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+ "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-finite": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz",
+ "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-fullwidth-code-point": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+ "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-extglob": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-hexadecimal": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz",
+ "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==",
+ "dev": true
+ },
+ "node_modules/is-negative-zero": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz",
+ "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
+ "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-obj": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
+ "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-plain-obj": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
+ "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-plain-object": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+ "dev": true,
+ "dependencies": {
+ "isobject": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-plain-object/node_modules/isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-posix-bracket": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz",
+ "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=",
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-primitive": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
+ "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=",
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-regex": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz",
+ "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==",
+ "dev": true,
+ "dependencies": {
+ "has-symbols": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/is-regexp": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-2.1.0.tgz",
+ "integrity": "sha512-OZ4IlER3zmRIoB9AqNhEggVxqIH4ofDns5nRrPS6yQxXE1TPCUpFznBfRQmQa8uC+pXqjMnukiJBxCisIxiLGA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/is-stream": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
+ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-symbol": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz",
+ "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==",
+ "dev": true,
+ "dependencies": {
+ "has-symbols": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
+ "dev": true
+ },
+ "node_modules/is-utf8": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+ "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
+ "dev": true
+ },
+ "node_modules/is-whitespace-character": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz",
+ "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==",
+ "dev": true
+ },
+ "node_modules/is-windows": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-word-character": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz",
+ "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==",
+ "dev": true
+ },
+ "node_modules/isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+ "dev": true
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+ "dev": true
+ },
+ "node_modules/isobject": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+ "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "isarray": "1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/isstream": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
+ "dev": true
+ },
+ "node_modules/istanbul": {
+ "version": "1.0.0-alpha.2",
+ "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-1.0.0-alpha.2.tgz",
+ "integrity": "sha1-BglrwI6Yuq10Sq5Gli2N+frGPQg=",
+ "dev": true,
+ "dependencies": {
+ "abbrev": "1.0.x",
+ "async": "1.x",
+ "istanbul-api": "^1.0.0-alpha",
+ "js-yaml": "3.x",
+ "mkdirp": "0.5.x",
+ "nopt": "3.x",
+ "which": "^1.1.1",
+ "wordwrap": "^1.0.0"
+ },
+ "bin": {
+ "istanbul": "lib/cli.js"
+ }
+ },
+ "node_modules/istanbul-api": {
+ "version": "1.3.7",
+ "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-1.3.7.tgz",
+ "integrity": "sha512-4/ApBnMVeEPG3EkSzcw25wDe4N66wxwn+KKn6b47vyek8Xb3NBAcg4xfuQbS7BqcZuTX4wxfD5lVagdggR3gyA==",
+ "dev": true,
+ "dependencies": {
+ "async": "^2.1.4",
+ "fileset": "^2.0.2",
+ "istanbul-lib-coverage": "^1.2.1",
+ "istanbul-lib-hook": "^1.2.2",
+ "istanbul-lib-instrument": "^1.10.2",
+ "istanbul-lib-report": "^1.1.5",
+ "istanbul-lib-source-maps": "^1.2.6",
+ "istanbul-reports": "^1.5.1",
+ "js-yaml": "^3.7.0",
+ "mkdirp": "^0.5.1",
+ "once": "^1.4.0"
+ }
+ },
+ "node_modules/istanbul-api/node_modules/async": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
+ "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
+ "dev": true,
+ "dependencies": {
+ "lodash": "^4.17.14"
+ }
+ },
+ "node_modules/istanbul-lib-coverage": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.1.tgz",
+ "integrity": "sha512-PzITeunAgyGbtY1ibVIUiV679EFChHjoMNRibEIobvmrCRaIgwLxNucOSimtNWUhEib/oO7QY2imD75JVgCJWQ==",
+ "dev": true
+ },
+ "node_modules/istanbul-lib-hook": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.2.2.tgz",
+ "integrity": "sha512-/Jmq7Y1VeHnZEQ3TL10VHyb564mn6VrQXHchON9Jf/AEcmQ3ZIiyD1BVzNOKTZf/G3gE+kiGK6SmpF9y3qGPLw==",
+ "dev": true,
+ "dependencies": {
+ "append-transform": "^0.4.0"
+ }
+ },
+ "node_modules/istanbul-lib-instrument": {
+ "version": "1.10.2",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.2.tgz",
+ "integrity": "sha512-aWHxfxDqvh/ZlxR8BBaEPVSWDPUkGD63VjGQn3jcw8jCp7sHEMKcrj4xfJn/ABzdMEHiQNyvDQhqm5o8+SQg7A==",
+ "dev": true,
+ "dependencies": {
+ "babel-generator": "^6.18.0",
+ "babel-template": "^6.16.0",
+ "babel-traverse": "^6.18.0",
+ "babel-types": "^6.18.0",
+ "babylon": "^6.18.0",
+ "istanbul-lib-coverage": "^1.2.1",
+ "semver": "^5.3.0"
+ }
+ },
+ "node_modules/istanbul-lib-report": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.5.tgz",
+ "integrity": "sha512-UsYfRMoi6QO/doUshYNqcKJqVmFe9w51GZz8BS3WB0lYxAllQYklka2wP9+dGZeHYaWIdcXUx8JGdbqaoXRXzw==",
+ "dev": true,
+ "dependencies": {
+ "istanbul-lib-coverage": "^1.2.1",
+ "mkdirp": "^0.5.1",
+ "path-parse": "^1.0.5",
+ "supports-color": "^3.1.2"
+ }
+ },
+ "node_modules/istanbul-lib-report/node_modules/has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/istanbul-lib-report/node_modules/supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/istanbul-lib-source-maps": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.6.tgz",
+ "integrity": "sha512-TtbsY5GIHgbMsMiRw35YBHGpZ1DVFEO19vxxeiDMYaeOFOCzfnYVxvl6pOUIZR4dtPhAGpSMup8OyF8ubsaqEg==",
+ "dev": true,
+ "dependencies": {
+ "debug": "^3.1.0",
+ "istanbul-lib-coverage": "^1.2.1",
+ "mkdirp": "^0.5.1",
+ "rimraf": "^2.6.1",
+ "source-map": "^0.5.3"
+ }
+ },
+ "node_modules/istanbul-lib-source-maps/node_modules/debug": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+ "dev": true,
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
+ "node_modules/istanbul-lib-source-maps/node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "node_modules/istanbul-lib-source-maps/node_modules/source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/istanbul-reports": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.5.1.tgz",
+ "integrity": "sha512-+cfoZ0UXzWjhAdzosCPP3AN8vvef8XDkWtTfgaN+7L3YTpNYITnCaEkceo5SEYy644VkHka/P1FvkWvrG/rrJw==",
+ "dev": true,
+ "dependencies": {
+ "handlebars": "^4.0.3"
+ }
+ },
+ "node_modules/istanbul/node_modules/abbrev": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz",
+ "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=",
+ "dev": true
+ },
+ "node_modules/iterall": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.3.0.tgz",
+ "integrity": "sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==",
+ "dev": true
+ },
+ "node_modules/jest-docblock": {
+ "version": "21.3.0-beta.11",
+ "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-21.3.0-beta.11.tgz",
+ "integrity": "sha512-sxSwZUm7JyCO8dverup5g/OKJhjYRrBdgEdezIO1qAmMGWuza7ewovpfDmxp+JLvlm0i2WRFKUQNNIMGmPGTVg==",
+ "dev": true,
+ "dependencies": {
+ "detect-newline": "^2.1.0"
+ }
+ },
+ "node_modules/jest-get-type": {
+ "version": "21.2.0",
+ "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-21.2.0.tgz",
+ "integrity": "sha512-y2fFw3C+D0yjNSDp7ab1kcd6NUYfy3waPTlD8yWkAtiocJdBRQqNoRqVfMNxgj+IjT0V5cBIHJO0z9vuSSZ43Q==",
+ "dev": true
+ },
+ "node_modules/jest-validate": {
+ "version": "21.1.0",
+ "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-21.1.0.tgz",
+ "integrity": "sha512-xS0cyErNWpsLFlGkn/b87pk/Mv7J+mCTs8hQ4KmtOIIoM1sHYobXII8AtkoN8FC7E3+Ptxjo+/3xWk6LK1dKcw==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.0.1",
+ "jest-get-type": "^21.0.2",
+ "leven": "^2.1.0",
+ "pretty-format": "^21.1.0"
+ }
+ },
+ "node_modules/js-base64": {
+ "version": "2.6.4",
+ "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz",
+ "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==",
+ "dev": true
+ },
+ "node_modules/js-tokens": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
+ "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
+ "dev": true
+ },
+ "node_modules/js-yaml": {
+ "version": "3.14.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz",
+ "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==",
+ "dev": true,
+ "dependencies": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/jsbn": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
+ "dev": true
+ },
+ "node_modules/jsesc": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
+ "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=",
+ "dev": true,
+ "bin": {
+ "jsesc": "bin/jsesc"
+ }
+ },
+ "node_modules/jshint": {
+ "version": "2.10.3",
+ "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.10.3.tgz",
+ "integrity": "sha512-d8AoXcNNYzmm7cdmulQ3dQApbrPYArtVBO6n4xOICe4QsXGNHCAKDcFORzqP52LhK61KX0VhY39yYzCsNq+bxQ==",
+ "dev": true,
+ "dependencies": {
+ "cli": "~1.0.0",
+ "console-browserify": "1.1.x",
+ "exit": "0.1.x",
+ "htmlparser2": "3.8.x",
+ "lodash": "~4.17.11",
+ "minimatch": "~3.0.2",
+ "shelljs": "0.3.x",
+ "strip-json-comments": "1.0.x"
+ },
+ "bin": {
+ "jshint": "bin/jshint"
+ }
+ },
+ "node_modules/jshint/node_modules/strip-json-comments": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz",
+ "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=",
+ "dev": true,
+ "bin": {
+ "strip-json-comments": "cli.js"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/json-parse-better-errors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
+ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
+ "dev": true
+ },
+ "node_modules/json-schema": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
+ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
+ "dev": true
+ },
+ "node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "node_modules/json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
+ "dev": true
+ },
+ "node_modules/json-stringify-safe": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
+ "dev": true
+ },
+ "node_modules/json5": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
+ "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=",
+ "dev": true,
+ "bin": {
+ "json5": "lib/cli.js"
+ }
+ },
+ "node_modules/jsprim": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
+ "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
+ "dev": true,
+ "engines": [
+ "node >=0.6.0"
+ ],
+ "dependencies": {
+ "assert-plus": "1.0.0",
+ "extsprintf": "1.3.0",
+ "json-schema": "0.2.3",
+ "verror": "1.10.0"
+ }
+ },
+ "node_modules/kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "dependencies": {
+ "is-buffer": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/known-css-properties": {
+ "version": "0.14.0",
+ "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.14.0.tgz",
+ "integrity": "sha512-P+0a/gBzLgVlCnK8I7VcD0yuYJscmWn66wH9tlKsQnmVdg689tLEmziwB9PuazZYLkcm07fvWOKCJJqI55sD5Q==",
+ "dev": true
+ },
+ "node_modules/lcid": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz",
+ "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==",
+ "dev": true,
+ "dependencies": {
+ "invert-kv": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/leven": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz",
+ "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/levn": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+ "dev": true,
+ "dependencies": {
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/livereload-js": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-2.4.0.tgz",
+ "integrity": "sha512-XPQH8Z2GDP/Hwz2PCDrh2mth4yFejwA1OZ/81Ti3LgKyhDcEjsSsqFWZojHG0va/duGd+WyosY7eXLDoOyqcPw==",
+ "dev": true
+ },
+ "node_modules/load-json-file": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
+ "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
+ "dev": true,
+ "dependencies": {
+ "graceful-fs": "^4.1.2",
+ "parse-json": "^2.2.0",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0",
+ "strip-bom": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/locate-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^3.0.0",
+ "path-exists": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/locate-path/node_modules/path-exists": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+ "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/lodash": {
+ "version": "4.17.20",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
+ "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
+ "dev": true
+ },
+ "node_modules/lodash.unescape": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz",
+ "integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=",
+ "dev": true
+ },
+ "node_modules/log-symbols": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz",
+ "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/longest-streak": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz",
+ "integrity": "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==",
+ "dev": true
+ },
+ "node_modules/loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "dev": true,
+ "dependencies": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ },
+ "bin": {
+ "loose-envify": "cli.js"
+ }
+ },
+ "node_modules/loud-rejection": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
+ "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=",
+ "dev": true,
+ "dependencies": {
+ "currently-unhandled": "^0.4.1",
+ "signal-exit": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-3.2.0.tgz",
+ "integrity": "sha1-cXibO39Tmb7IVl3aOKow0qCX7+4=",
+ "dev": true,
+ "dependencies": {
+ "pseudomap": "^1.0.1"
+ }
+ },
+ "node_modules/map-age-cleaner": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
+ "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==",
+ "dev": true,
+ "dependencies": {
+ "p-defer": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/map-cache": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+ "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/map-obj": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
+ "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/map-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
+ "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
+ "dev": true,
+ "dependencies": {
+ "object-visit": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/markdown-escapes": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz",
+ "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==",
+ "dev": true
+ },
+ "node_modules/markdown-table": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.3.tgz",
+ "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==",
+ "dev": true
+ },
+ "node_modules/math-random": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz",
+ "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==",
+ "dev": true,
+ "optional": true
+ },
+ "node_modules/mathml-tag-names": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz",
+ "integrity": "sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==",
+ "dev": true
+ },
+ "node_modules/maxmin": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/maxmin/-/maxmin-2.1.0.tgz",
+ "integrity": "sha1-TTsiCQPZXu5+t6x/qGTnLcCaMWY=",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.0.0",
+ "figures": "^1.0.1",
+ "gzip-size": "^3.0.0",
+ "pretty-bytes": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/maxmin/node_modules/ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/maxmin/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/maxmin/node_modules/figures": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz",
+ "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=",
+ "dev": true,
+ "dependencies": {
+ "escape-string-regexp": "^1.0.5",
+ "object-assign": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/maxmin/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/mdast-util-compact": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mdast-util-compact/-/mdast-util-compact-1.0.4.tgz",
+ "integrity": "sha512-3YDMQHI5vRiS2uygEFYaqckibpJtKq5Sj2c8JioeOQBU6INpKbdWzfyLqFFnDwEcEnRFIdMsguzs5pC1Jp4Isg==",
+ "dev": true,
+ "dependencies": {
+ "unist-util-visit": "^1.1.0"
+ }
+ },
+ "node_modules/mem": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz",
+ "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==",
+ "dev": true,
+ "dependencies": {
+ "map-age-cleaner": "^0.1.1",
+ "mimic-fn": "^2.0.0",
+ "p-is-promise": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/mem/node_modules/mimic-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/meow": {
+ "version": "3.7.0",
+ "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
+ "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
+ "dev": true,
+ "dependencies": {
+ "camelcase-keys": "^2.0.0",
+ "decamelize": "^1.1.2",
+ "loud-rejection": "^1.0.0",
+ "map-obj": "^1.0.1",
+ "minimist": "^1.1.3",
+ "normalize-package-data": "^2.3.4",
+ "object-assign": "^4.0.1",
+ "read-pkg-up": "^1.0.1",
+ "redent": "^1.0.0",
+ "trim-newlines": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/micromatch": {
+ "version": "2.3.11",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
+ "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "arr-diff": "^2.0.0",
+ "array-unique": "^0.2.1",
+ "braces": "^1.8.2",
+ "expand-brackets": "^0.1.4",
+ "extglob": "^0.3.1",
+ "filename-regex": "^2.0.0",
+ "is-extglob": "^1.0.0",
+ "is-glob": "^2.0.1",
+ "kind-of": "^3.0.2",
+ "normalize-path": "^2.0.1",
+ "object.omit": "^2.0.0",
+ "parse-glob": "^3.0.4",
+ "regex-cache": "^0.4.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.44.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
+ "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.27",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
+ "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
+ "dev": true,
+ "dependencies": {
+ "mime-db": "1.44.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mimic-fn": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
+ "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/minimist": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
+ "dev": true
+ },
+ "node_modules/minimist-options": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-3.0.2.tgz",
+ "integrity": "sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ==",
+ "dev": true,
+ "dependencies": {
+ "arrify": "^1.0.1",
+ "is-plain-obj": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/minipass": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz",
+ "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==",
+ "dev": true,
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/minizlib": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
+ "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
+ "dev": true,
+ "dependencies": {
+ "minipass": "^3.0.0",
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/mixin-deep": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
+ "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
+ "dev": true,
+ "dependencies": {
+ "for-in": "^1.0.2",
+ "is-extendable": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/mixin-deep/node_modules/is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+ "dev": true,
+ "dependencies": {
+ "is-plain-object": "^2.0.4"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/mkdirp": {
+ "version": "0.5.5",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
+ "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
+ "dev": true,
+ "dependencies": {
+ "minimist": "^1.2.5"
+ },
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ }
+ },
+ "node_modules/mocha": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.0.tgz",
+ "integrity": "sha512-qwfFgY+7EKAAUAdv7VYMZQknI7YJSGesxHyhn6qD52DV8UcSZs5XwCifcZGMVIE4a5fbmhvbotxC0DLQ0oKohQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-colors": "3.2.3",
+ "browser-stdout": "1.3.1",
+ "debug": "3.2.6",
+ "diff": "3.5.0",
+ "escape-string-regexp": "1.0.5",
+ "find-up": "3.0.0",
+ "glob": "7.1.3",
+ "growl": "1.10.5",
+ "he": "1.2.0",
+ "js-yaml": "3.13.1",
+ "log-symbols": "2.2.0",
+ "minimatch": "3.0.4",
+ "mkdirp": "0.5.1",
+ "ms": "2.1.1",
+ "node-environment-flags": "1.0.5",
+ "object.assign": "4.1.0",
+ "strip-json-comments": "2.0.1",
+ "supports-color": "6.0.0",
+ "which": "1.3.1",
+ "wide-align": "1.1.3",
+ "yargs": "13.2.2",
+ "yargs-parser": "13.0.0",
+ "yargs-unparser": "1.5.0"
+ },
+ "bin": {
+ "_mocha": "bin/_mocha",
+ "mocha": "bin/mocha"
+ },
+ "engines": {
+ "node": ">= 6.0.0"
+ }
+ },
+ "node_modules/mocha/node_modules/debug": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+ "dev": true,
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
+ "node_modules/mocha/node_modules/find-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/mocha/node_modules/glob": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
+ "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
+ "dev": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/mocha/node_modules/js-yaml": {
+ "version": "3.13.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
+ "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
+ "dev": true,
+ "dependencies": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/mocha/node_modules/minimist": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
+ "dev": true
+ },
+ "node_modules/mocha/node_modules/mkdirp": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+ "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+ "dev": true,
+ "dependencies": {
+ "minimist": "0.0.8"
+ },
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ }
+ },
+ "node_modules/mocha/node_modules/ms": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
+ "dev": true
+ },
+ "node_modules/mocha/node_modules/strip-json-comments": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/mocha/node_modules/supports-color": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz",
+ "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ },
+ "node_modules/mute-stream": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
+ "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
+ "dev": true
+ },
+ "node_modules/nan": {
+ "version": "2.14.2",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz",
+ "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==",
+ "dev": true
+ },
+ "node_modules/nanomatch": {
+ "version": "1.2.13",
+ "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
+ "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
+ "dev": true,
+ "dependencies": {
+ "arr-diff": "^4.0.0",
+ "array-unique": "^0.3.2",
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "fragment-cache": "^0.2.1",
+ "is-windows": "^1.0.2",
+ "kind-of": "^6.0.2",
+ "object.pick": "^1.3.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/nanomatch/node_modules/arr-diff": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+ "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/nanomatch/node_modules/array-unique": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/nanomatch/node_modules/kind-of": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
+ "dev": true
+ },
+ "node_modules/neo-async": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
+ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
+ "dev": true
+ },
+ "node_modules/nice-try": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
+ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
+ "dev": true
+ },
+ "node_modules/node-environment-flags": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz",
+ "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==",
+ "dev": true,
+ "dependencies": {
+ "object.getownpropertydescriptors": "^2.0.3",
+ "semver": "^5.7.0"
+ }
+ },
+ "node_modules/node-gyp": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz",
+ "integrity": "sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==",
+ "dev": true,
+ "dependencies": {
+ "env-paths": "^2.2.0",
+ "glob": "^7.1.4",
+ "graceful-fs": "^4.2.3",
+ "nopt": "^5.0.0",
+ "npmlog": "^4.1.2",
+ "request": "^2.88.2",
+ "rimraf": "^3.0.2",
+ "semver": "^7.3.2",
+ "tar": "^6.0.2",
+ "which": "^2.0.2"
+ },
+ "bin": {
+ "node-gyp": "bin/node-gyp.js"
+ },
+ "engines": {
+ "node": ">= 10.12.0"
+ }
+ },
+ "node_modules/node-gyp/node_modules/nopt": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
+ "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
+ "dev": true,
+ "dependencies": {
+ "abbrev": "1"
+ },
+ "bin": {
+ "nopt": "bin/nopt.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/node-gyp/node_modules/rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "dev": true,
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ }
+ },
+ "node_modules/node-gyp/node_modules/semver": {
+ "version": "7.3.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
+ "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/node-gyp/node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/node-releases": {
+ "version": "1.1.66",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.66.tgz",
+ "integrity": "sha512-JHEQ1iWPGK+38VLB2H9ef2otU4l8s3yAMt9Xf934r6+ojCYDMHPMqvCc9TnzfeFSP1QEOeU6YZEd3+De0LTCgg==",
+ "dev": true
+ },
+ "node_modules/node-sass": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-5.0.0.tgz",
+ "integrity": "sha512-opNgmlu83ZCF792U281Ry7tak9IbVC+AKnXGovcQ8LG8wFaJv6cLnRlc6DIHlmNxWEexB5bZxi9SZ9JyUuOYjw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "dependencies": {
+ "async-foreach": "^0.1.3",
+ "chalk": "^1.1.1",
+ "cross-spawn": "^7.0.3",
+ "gaze": "^1.0.0",
+ "get-stdin": "^4.0.1",
+ "glob": "^7.0.3",
+ "lodash": "^4.17.15",
+ "meow": "^3.7.0",
+ "mkdirp": "^0.5.1",
+ "nan": "^2.13.2",
+ "node-gyp": "^7.1.0",
+ "npmlog": "^4.0.0",
+ "request": "^2.88.0",
+ "sass-graph": "2.2.5",
+ "stdout-stream": "^1.4.0",
+ "true-case-path": "^1.0.2"
+ },
+ "bin": {
+ "node-sass": "bin/node-sass"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/node-sass/node_modules/ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/node-sass/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/node-sass/node_modules/cross-spawn": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+ "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "dev": true,
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/node-sass/node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/node-sass/node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/node-sass/node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/node-sass/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/node-sass/node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/node-wp-i18n": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/node-wp-i18n/-/node-wp-i18n-1.2.3.tgz",
+ "integrity": "sha512-YMzMcsjXbGYDB9vHyb289CYXAGmXhcNLbeTlOnWgPNkZd9xrovcbRd7cQyKd9BQHOjS7Nw8WCbJ7nvtR7rc0rg==",
+ "dev": true,
+ "dependencies": {
+ "bluebird": "^3.4.1",
+ "gettext-parser": "^3.1.0",
+ "glob": "^7.0.5",
+ "lodash": "^4.14.2",
+ "minimist": "^1.2.0",
+ "mkdirp": "^0.5.1",
+ "tmp": "^0.0.33"
+ },
+ "bin": {
+ "wpi18n": "bin/wpi18n"
+ }
+ },
+ "node_modules/nopt": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
+ "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=",
+ "dev": true,
+ "dependencies": {
+ "abbrev": "1"
+ },
+ "bin": {
+ "nopt": "bin/nopt.js"
+ }
+ },
+ "node_modules/normalize-package-data": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+ "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+ "dev": true,
+ "dependencies": {
+ "hosted-git-info": "^2.1.4",
+ "resolve": "^1.10.0",
+ "semver": "2 || 3 || 4 || 5",
+ "validate-npm-package-license": "^3.0.1"
+ }
+ },
+ "node_modules/normalize-path": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "remove-trailing-separator": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/normalize-range": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+ "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/normalize-selector": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/normalize-selector/-/normalize-selector-0.2.0.tgz",
+ "integrity": "sha1-0LFF62kRicY6eNIB3E/bEpPvDAM=",
+ "dev": true
+ },
+ "node_modules/npm-run-path": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
+ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
+ "dev": true,
+ "dependencies": {
+ "path-key": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/npmlog": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
+ "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
+ "dev": true,
+ "dependencies": {
+ "are-we-there-yet": "~1.1.2",
+ "console-control-strings": "~1.1.0",
+ "gauge": "~2.7.3",
+ "set-blocking": "~2.0.0"
+ }
+ },
+ "node_modules/num2fraction": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz",
+ "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=",
+ "dev": true
+ },
+ "node_modules/number-is-nan": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/oauth-sign": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
+ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-copy": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
+ "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
+ "dev": true,
+ "dependencies": {
+ "copy-descriptor": "^0.1.0",
+ "define-property": "^0.2.5",
+ "kind-of": "^3.0.3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-copy/node_modules/define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "dependencies": {
+ "is-descriptor": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz",
+ "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==",
+ "dev": true
+ },
+ "node_modules/object-keys": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object-visit": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
+ "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
+ "dev": true,
+ "dependencies": {
+ "isobject": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-visit/node_modules/isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object.assign": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
+ "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
+ "dev": true,
+ "dependencies": {
+ "define-properties": "^1.1.2",
+ "function-bind": "^1.1.1",
+ "has-symbols": "^1.0.0",
+ "object-keys": "^1.0.11"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.getownpropertydescriptors": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz",
+ "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==",
+ "dev": true,
+ "dependencies": {
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.17.0-next.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/object.omit": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
+ "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "for-own": "^0.1.4",
+ "is-extendable": "^0.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object.pick": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
+ "dev": true,
+ "dependencies": {
+ "isobject": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object.pick/node_modules/isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "dev": true,
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/onetime": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
+ "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
+ "dev": true,
+ "dependencies": {
+ "mimic-fn": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/optionator": {
+ "version": "0.8.3",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
+ "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
+ "dev": true,
+ "dependencies": {
+ "deep-is": "~0.1.3",
+ "fast-levenshtein": "~2.0.6",
+ "levn": "~0.3.0",
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2",
+ "word-wrap": "~1.2.3"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/os-homedir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+ "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/os-locale": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz",
+ "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==",
+ "dev": true,
+ "dependencies": {
+ "execa": "^1.0.0",
+ "lcid": "^2.0.0",
+ "mem": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/os-tmpdir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/output-file-sync": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-1.1.2.tgz",
+ "integrity": "sha1-0KM+7+YaIF+suQCS6CZZjVJFznY=",
+ "dev": true,
+ "dependencies": {
+ "graceful-fs": "^4.1.4",
+ "mkdirp": "^0.5.1",
+ "object-assign": "^4.1.0"
+ }
+ },
+ "node_modules/p-defer": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",
+ "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/p-finally": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
+ "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/p-is-promise": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz",
+ "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "dependencies": {
+ "callsites": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/parse-entities": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-1.2.2.tgz",
+ "integrity": "sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg==",
+ "dev": true,
+ "dependencies": {
+ "character-entities": "^1.0.0",
+ "character-entities-legacy": "^1.0.0",
+ "character-reference-invalid": "^1.0.0",
+ "is-alphanumerical": "^1.0.0",
+ "is-decimal": "^1.0.0",
+ "is-hexadecimal": "^1.0.0"
+ }
+ },
+ "node_modules/parse-glob": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
+ "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "glob-base": "^0.3.0",
+ "is-dotfile": "^1.0.0",
+ "is-extglob": "^1.0.0",
+ "is-glob": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/parse-json": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
+ "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
+ "dev": true,
+ "dependencies": {
+ "error-ex": "^1.2.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/parse5": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz",
+ "integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/pascalcase": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
+ "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-dirname": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
+ "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=",
+ "dev": true
+ },
+ "node_modules/path-exists": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
+ "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
+ "dev": true,
+ "dependencies": {
+ "pinkie-promise": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+ "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/path-parse": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
+ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
+ "dev": true
+ },
+ "node_modules/path-root": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz",
+ "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=",
+ "dev": true,
+ "dependencies": {
+ "path-root-regex": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-root-regex": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz",
+ "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-type": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
+ "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
+ "dev": true,
+ "dependencies": {
+ "graceful-fs": "^4.1.2",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/pathval": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz",
+ "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/performance-now": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
+ "dev": true
+ },
+ "node_modules/picomatch": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
+ "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/pinkie": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+ "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/pinkie-promise": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+ "dev": true,
+ "dependencies": {
+ "pinkie": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/posix-character-classes": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
+ "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "7.0.35",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz",
+ "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.4.2",
+ "source-map": "^0.6.1",
+ "supports-color": "^6.1.0"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/postcss-html": {
+ "version": "0.36.0",
+ "resolved": "https://registry.npmjs.org/postcss-html/-/postcss-html-0.36.0.tgz",
+ "integrity": "sha512-HeiOxGcuwID0AFsNAL0ox3mW6MHH5cstWN1Z3Y+n6H+g12ih7LHdYxWwEA/QmrebctLjo79xz9ouK3MroHwOJw==",
+ "dev": true,
+ "dependencies": {
+ "htmlparser2": "^3.10.0"
+ }
+ },
+ "node_modules/postcss-html/node_modules/entities": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
+ "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==",
+ "dev": true
+ },
+ "node_modules/postcss-html/node_modules/htmlparser2": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
+ "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
+ "dev": true,
+ "dependencies": {
+ "domelementtype": "^1.3.1",
+ "domhandler": "^2.3.0",
+ "domutils": "^1.5.1",
+ "entities": "^1.1.1",
+ "inherits": "^2.0.1",
+ "readable-stream": "^3.1.1"
+ }
+ },
+ "node_modules/postcss-html/node_modules/readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/postcss-jsx": {
+ "version": "0.36.4",
+ "resolved": "https://registry.npmjs.org/postcss-jsx/-/postcss-jsx-0.36.4.tgz",
+ "integrity": "sha512-jwO/7qWUvYuWYnpOb0+4bIIgJt7003pgU3P6nETBLaOyBXuTD55ho21xnals5nBrlpTIFodyd3/jBi6UO3dHvA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/core": ">=7.2.2"
+ }
+ },
+ "node_modules/postcss-less": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/postcss-less/-/postcss-less-1.1.3.tgz",
+ "integrity": "sha512-WS0wsQxRm+kmN8wEYAGZ3t4lnoNfoyx9EJZrhiPR1K0lMHR0UNWnz52Ya5QRXChHtY75Ef+kDc05FpnBujebgw==",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^5.2.16"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/postcss-less/node_modules/ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-less/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-less/node_modules/chalk/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/postcss-less/node_modules/has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-less/node_modules/postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/postcss-less/node_modules/source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-less/node_modules/supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/postcss-markdown": {
+ "version": "0.36.0",
+ "resolved": "https://registry.npmjs.org/postcss-markdown/-/postcss-markdown-0.36.0.tgz",
+ "integrity": "sha512-rl7fs1r/LNSB2bWRhyZ+lM/0bwKv9fhl38/06gF6mKMo/NPnp55+K1dSTosSVjFZc0e1ppBlu+WT91ba0PMBfQ==",
+ "dev": true,
+ "dependencies": {
+ "remark": "^10.0.1",
+ "unist-util-find-all-after": "^1.0.2"
+ }
+ },
+ "node_modules/postcss-media-query-parser": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz",
+ "integrity": "sha1-J7Ocb02U+Bsac7j3Y1HGCeXO8kQ=",
+ "dev": true
+ },
+ "node_modules/postcss-reporter": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-6.0.1.tgz",
+ "integrity": "sha512-LpmQjfRWyabc+fRygxZjpRxfhRf9u/fdlKf4VHG4TSPbV2XNsuISzYW1KL+1aQzx53CAppa1bKG4APIB/DOXXw==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.4.1",
+ "lodash": "^4.17.11",
+ "log-symbols": "^2.2.0",
+ "postcss": "^7.0.7"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/postcss-resolve-nested-selector": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz",
+ "integrity": "sha1-Kcy8fDfe36wwTp//C/FZaz9qDk4=",
+ "dev": true
+ },
+ "node_modules/postcss-safe-parser": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-4.0.2.tgz",
+ "integrity": "sha512-Uw6ekxSWNLCPesSv/cmqf2bY/77z11O7jZGPax3ycZMFU/oi2DMH9i89AdHc1tRwFg/arFoEwX0IS3LCUxJh1g==",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^7.0.26"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/postcss-sass": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/postcss-sass/-/postcss-sass-0.3.5.tgz",
+ "integrity": "sha512-B5z2Kob4xBxFjcufFnhQ2HqJQ2y/Zs/ic5EZbCywCkxKd756Q40cIQ/veRDwSrw1BF6+4wUgmpm0sBASqVi65A==",
+ "dev": true,
+ "dependencies": {
+ "gonzales-pe": "^4.2.3",
+ "postcss": "^7.0.1"
+ }
+ },
+ "node_modules/postcss-scss": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-1.0.2.tgz",
+ "integrity": "sha1-/0XPM1S4ee6JpOtoaA9GrJuxT5Q=",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^6.0.3"
+ }
+ },
+ "node_modules/postcss-scss/node_modules/postcss": {
+ "version": "6.0.23",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
+ "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.4.1",
+ "source-map": "^0.6.1",
+ "supports-color": "^5.4.0"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/postcss-selector-parser": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz",
+ "integrity": "sha1-+UN3iGBsPJrO4W/+jYsWKX8nu5A=",
+ "dev": true,
+ "dependencies": {
+ "flatten": "^1.0.2",
+ "indexes-of": "^1.0.1",
+ "uniq": "^1.0.1"
+ }
+ },
+ "node_modules/postcss-syntax": {
+ "version": "0.36.2",
+ "resolved": "https://registry.npmjs.org/postcss-syntax/-/postcss-syntax-0.36.2.tgz",
+ "integrity": "sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==",
+ "dev": true
+ },
+ "node_modules/postcss-value-parser": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz",
+ "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==",
+ "dev": true
+ },
+ "node_modules/postcss-values-parser": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-values-parser/-/postcss-values-parser-1.3.1.tgz",
+ "integrity": "sha512-chFn9CnFAAUpQ3cwrxvVjKB8c0y6BfONv6eapndJoTXJ3h8fr1uAiue8lGP3rUIpBI2KgJGdgCVk9KNvXh0n6A==",
+ "dev": true,
+ "dependencies": {
+ "flatten": "^1.0.2",
+ "indexes-of": "^1.0.1",
+ "uniq": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/postcss/node_modules/supports-color": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+ "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/prelude-ls": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/preserve": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
+ "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=",
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/prettier": {
+ "resolved": "git+ssh://git@github.com/automattic/calypso-prettier.git#c56b42511ec98ba6d8f72b6c391e0a626e90f531",
+ "dev": true,
+ "dependencies": {
+ "babel-code-frame": "7.0.0-beta.3",
+ "babylon": "7.0.0-beta.34",
+ "camelcase": "4.1.0",
+ "chalk": "2.1.0",
+ "cjk-regex": "1.0.2",
+ "cosmiconfig": "3.1.0",
+ "dashify": "0.2.2",
+ "diff": "3.2.0",
+ "editorconfig": "0.14.2",
+ "editorconfig-to-prettier": "0.0.6",
+ "emoji-regex": "6.5.1",
+ "escape-string-regexp": "1.0.5",
+ "esutils": "2.0.2",
+ "flow-parser": "0.59.0",
+ "get-stream": "3.0.0",
+ "globby": "6.1.0",
+ "graphql": "0.10.5",
+ "ignore": "3.3.7",
+ "jest-docblock": "21.3.0-beta.11",
+ "jest-validate": "21.1.0",
+ "leven": "2.1.0",
+ "mem": "1.1.0",
+ "minimatch": "3.0.4",
+ "minimist": "1.2.0",
+ "parse5": "3.0.3",
+ "path-root": "0.1.1",
+ "postcss-less": "1.1.3",
+ "postcss-media-query-parser": "0.2.3",
+ "postcss-scss": "1.0.2",
+ "postcss-selector-parser": "2.2.3",
+ "postcss-values-parser": "1.3.1",
+ "remark-frontmatter": "1.1.0",
+ "remark-parse": "4.0.0",
+ "semver": "5.4.1",
+ "string-width": "2.1.1",
+ "typescript": "2.6.2",
+ "typescript-eslint-parser": "9.0.1",
+ "unicode-regex": "1.0.1",
+ "unified": "6.1.6"
+ },
+ "bin": {
+ "prettier": "bin/prettier.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/prettier/node_modules/babel-code-frame": {
+ "version": "7.0.0-beta.3",
+ "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-7.0.0-beta.3.tgz",
+ "integrity": "sha512-flMsJ9eSpShupt2Gwpka84DoMePvE4HlDObzdEc+1iNkacv3+NHlsJ7dMKmbnVA/AT22UhcGEBHwbJLoXWBO6Q==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.0.0",
+ "esutils": "^2.0.2",
+ "js-tokens": "^3.0.0"
+ }
+ },
+ "node_modules/prettier/node_modules/babylon": {
+ "version": "7.0.0-beta.34",
+ "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.34.tgz",
+ "integrity": "sha512-ribEzWEhWKKjY+1FdKCryo+HiN/1idPjUB8vyR5Yf221MtGzCd5+7OwPvWvYHerHHC2eJLr6MhvumbTocXGY7Q==",
+ "dev": true,
+ "bin": {
+ "babylon": "bin/babylon.js"
+ },
+ "engines": {
+ "node": ">=4.2.0"
+ }
+ },
+ "node_modules/prettier/node_modules/camelcase": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
+ "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/prettier/node_modules/chalk": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz",
+ "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^3.1.0",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/prettier/node_modules/diff": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz",
+ "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
+ "node_modules/prettier/node_modules/emoji-regex": {
+ "version": "6.5.1",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.5.1.tgz",
+ "integrity": "sha512-PAHp6TxrCy7MGMFidro8uikr+zlJJKJ/Q6mm2ExZ7HwkyR9lSVFfE3kt36qcwa24BQL7y0G9axycGjK1A/0uNQ==",
+ "dev": true
+ },
+ "node_modules/prettier/node_modules/esutils": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
+ "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/prettier/node_modules/get-stream": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
+ "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/prettier/node_modules/has-flag": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
+ "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/prettier/node_modules/ignore": {
+ "version": "3.3.7",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.7.tgz",
+ "integrity": "sha512-YGG3ejvBNHRqu0559EOxxNFihD0AjpvHlC/pdGKd3X3ofe+CoJkYazwNJYTNebqpPKN+VVQbh4ZFn1DivMNuHA==",
+ "dev": true
+ },
+ "node_modules/prettier/node_modules/mem": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz",
+ "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=",
+ "dev": true,
+ "dependencies": {
+ "mimic-fn": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/prettier/node_modules/minimist": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+ "dev": true
+ },
+ "node_modules/prettier/node_modules/semver": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
+ "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver"
+ }
+ },
+ "node_modules/prettier/node_modules/supports-color": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz",
+ "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/pretty-bytes": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-3.0.1.tgz",
+ "integrity": "sha1-J9AAjXeAY6C0gRuzXHnxvV1fvM8=",
+ "dev": true,
+ "dependencies": {
+ "number-is-nan": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/pretty-format": {
+ "version": "21.2.1",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-21.2.1.tgz",
+ "integrity": "sha512-ZdWPGYAnYfcVP8yKA3zFjCn8s4/17TeYH28MXuC8vTp0o21eXjbFGcOAXZEaDaOFJjc3h2qa7HQNHNshhvoh2A==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^3.0.0",
+ "ansi-styles": "^3.2.0"
+ }
+ },
+ "node_modules/pretty-format/node_modules/ansi-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/private": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz",
+ "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+ "dev": true
+ },
+ "node_modules/progress": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/pseudomap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
+ "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
+ "dev": true
+ },
+ "node_modules/psl": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
+ "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==",
+ "dev": true
+ },
+ "node_modules/pump": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+ "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+ "dev": true,
+ "dependencies": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
+ "node_modules/punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/qs": {
+ "version": "6.9.4",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz",
+ "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/quick-lru": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz",
+ "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/randomatic": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz",
+ "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-number": "^4.0.0",
+ "kind-of": "^6.0.0",
+ "math-random": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/randomatic/node_modules/is-number": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
+ "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==",
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/randomatic/node_modules/kind-of": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/raw-body": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz",
+ "integrity": "sha1-HQJ8K/oRasxmI7yo8AAWVyqH1CU=",
+ "dev": true,
+ "dependencies": {
+ "bytes": "1",
+ "string_decoder": "0.10"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/raw-body/node_modules/string_decoder": {
+ "version": "0.10.31",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
+ "dev": true
+ },
+ "node_modules/read-pkg": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
+ "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
+ "dev": true,
+ "dependencies": {
+ "load-json-file": "^1.0.0",
+ "normalize-package-data": "^2.3.2",
+ "path-type": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/read-pkg-up": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
+ "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
+ "dev": true,
+ "dependencies": {
+ "find-up": "^1.0.0",
+ "read-pkg": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readable-stream": {
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+ "dev": true,
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
+ "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "graceful-fs": "^4.1.11",
+ "micromatch": "^3.1.10",
+ "readable-stream": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/readdirp/node_modules/arr-diff": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+ "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readdirp/node_modules/array-unique": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readdirp/node_modules/braces": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "arr-flatten": "^1.1.0",
+ "array-unique": "^0.3.2",
+ "extend-shallow": "^2.0.1",
+ "fill-range": "^4.0.0",
+ "isobject": "^3.0.1",
+ "repeat-element": "^1.1.2",
+ "snapdragon": "^0.8.1",
+ "snapdragon-node": "^2.0.1",
+ "split-string": "^3.0.2",
+ "to-regex": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readdirp/node_modules/braces/node_modules/extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-extendable": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readdirp/node_modules/expand-brackets": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "debug": "^2.3.3",
+ "define-property": "^0.2.5",
+ "extend-shallow": "^2.0.1",
+ "posix-character-classes": "^0.1.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readdirp/node_modules/expand-brackets/node_modules/define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-descriptor": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readdirp/node_modules/expand-brackets/node_modules/extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-extendable": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readdirp/node_modules/expand-brackets/node_modules/is-accessor-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readdirp/node_modules/expand-brackets/node_modules/is-accessor-descriptor/node_modules/kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-buffer": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readdirp/node_modules/expand-brackets/node_modules/is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readdirp/node_modules/expand-brackets/node_modules/is-data-descriptor/node_modules/kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-buffer": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readdirp/node_modules/expand-brackets/node_modules/is-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-accessor-descriptor": "^0.1.6",
+ "is-data-descriptor": "^0.1.4",
+ "kind-of": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readdirp/node_modules/expand-brackets/node_modules/kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readdirp/node_modules/extglob": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "array-unique": "^0.3.2",
+ "define-property": "^1.0.0",
+ "expand-brackets": "^2.1.4",
+ "extend-shallow": "^2.0.1",
+ "fragment-cache": "^0.2.1",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readdirp/node_modules/extglob/node_modules/define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-descriptor": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readdirp/node_modules/extglob/node_modules/extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-extendable": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readdirp/node_modules/fill-range": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "extend-shallow": "^2.0.1",
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1",
+ "to-regex-range": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readdirp/node_modules/fill-range/node_modules/extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-extendable": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readdirp/node_modules/is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "kind-of": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readdirp/node_modules/is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "kind-of": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readdirp/node_modules/is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readdirp/node_modules/is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readdirp/node_modules/is-number/node_modules/kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-buffer": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readdirp/node_modules/isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readdirp/node_modules/kind-of": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readdirp/node_modules/micromatch": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "arr-diff": "^4.0.0",
+ "array-unique": "^0.3.2",
+ "braces": "^2.3.1",
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "extglob": "^2.0.4",
+ "fragment-cache": "^0.2.1",
+ "kind-of": "^6.0.2",
+ "nanomatch": "^1.2.9",
+ "object.pick": "^1.3.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readline2": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz",
+ "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=",
+ "dev": true,
+ "dependencies": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "mute-stream": "0.0.5"
+ }
+ },
+ "node_modules/readline2/node_modules/is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+ "dev": true,
+ "dependencies": {
+ "number-is-nan": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readline2/node_modules/mute-stream": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz",
+ "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=",
+ "dev": true
+ },
+ "node_modules/redent": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
+ "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=",
+ "dev": true,
+ "dependencies": {
+ "indent-string": "^2.1.0",
+ "strip-indent": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/regenerate": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
+ "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==",
+ "dev": true
+ },
+ "node_modules/regenerator-runtime": {
+ "version": "0.11.1",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
+ "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",
+ "dev": true
+ },
+ "node_modules/regenerator-transform": {
+ "version": "0.10.1",
+ "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz",
+ "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.18.0",
+ "babel-types": "^6.19.0",
+ "private": "^0.1.6"
+ }
+ },
+ "node_modules/regex-cache": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz",
+ "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-equal-shallow": "^0.1.3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/regex-not": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+ "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+ "dev": true,
+ "dependencies": {
+ "extend-shallow": "^3.0.2",
+ "safe-regex": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/regexpp": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz",
+ "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.5.0"
+ }
+ },
+ "node_modules/regexpu-core": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz",
+ "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=",
+ "dev": true,
+ "dependencies": {
+ "regenerate": "^1.2.1",
+ "regjsgen": "^0.2.0",
+ "regjsparser": "^0.1.4"
+ }
+ },
+ "node_modules/regjsgen": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz",
+ "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=",
+ "dev": true
+ },
+ "node_modules/regjsparser": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz",
+ "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=",
+ "dev": true,
+ "dependencies": {
+ "jsesc": "~0.5.0"
+ },
+ "bin": {
+ "regjsparser": "bin/parser"
+ }
+ },
+ "node_modules/regjsparser/node_modules/jsesc": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
+ "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=",
+ "dev": true,
+ "bin": {
+ "jsesc": "bin/jsesc"
+ }
+ },
+ "node_modules/remark": {
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/remark/-/remark-10.0.1.tgz",
+ "integrity": "sha512-E6lMuoLIy2TyiokHprMjcWNJ5UxfGQjaMSMhV+f4idM625UjjK4j798+gPs5mfjzDE6vL0oFKVeZM6gZVSVrzQ==",
+ "dev": true,
+ "dependencies": {
+ "remark-parse": "^6.0.0",
+ "remark-stringify": "^6.0.0",
+ "unified": "^7.0.0"
+ }
+ },
+ "node_modules/remark-frontmatter": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-1.1.0.tgz",
+ "integrity": "sha512-mLbYtwP9w1L9TA8dX+I/HyDF5lCpa0dmYvvW9Io+zUPpqEZ49QMKWb0hSpunpLVA+Squy0SowzSzjHVPbxWq1g==",
+ "dev": true,
+ "dependencies": {
+ "fault": "^1.0.1",
+ "xtend": "^4.0.1"
+ }
+ },
+ "node_modules/remark-parse": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-4.0.0.tgz",
+ "integrity": "sha512-XZgICP2gJ1MHU7+vQaRM+VA9HEL3X253uwUM/BGgx3iv6TH2B3bF3B8q00DKcyP9YrJV+/7WOWEWBFF/u8cIsw==",
+ "dev": true,
+ "dependencies": {
+ "collapse-white-space": "^1.0.2",
+ "is-alphabetical": "^1.0.0",
+ "is-decimal": "^1.0.0",
+ "is-whitespace-character": "^1.0.0",
+ "is-word-character": "^1.0.0",
+ "markdown-escapes": "^1.0.0",
+ "parse-entities": "^1.0.2",
+ "repeat-string": "^1.5.4",
+ "state-toggle": "^1.0.0",
+ "trim": "0.0.1",
+ "trim-trailing-lines": "^1.0.0",
+ "unherit": "^1.0.4",
+ "unist-util-remove-position": "^1.0.0",
+ "vfile-location": "^2.0.0",
+ "xtend": "^4.0.1"
+ }
+ },
+ "node_modules/remark-stringify": {
+ "version": "6.0.4",
+ "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-6.0.4.tgz",
+ "integrity": "sha512-eRWGdEPMVudijE/psbIDNcnJLRVx3xhfuEsTDGgH4GsFF91dVhw5nhmnBppafJ7+NWINW6C7ZwWbi30ImJzqWg==",
+ "dev": true,
+ "dependencies": {
+ "ccount": "^1.0.0",
+ "is-alphanumeric": "^1.0.0",
+ "is-decimal": "^1.0.0",
+ "is-whitespace-character": "^1.0.0",
+ "longest-streak": "^2.0.1",
+ "markdown-escapes": "^1.0.0",
+ "markdown-table": "^1.1.0",
+ "mdast-util-compact": "^1.0.0",
+ "parse-entities": "^1.0.2",
+ "repeat-string": "^1.5.4",
+ "state-toggle": "^1.0.0",
+ "stringify-entities": "^1.0.1",
+ "unherit": "^1.0.4",
+ "xtend": "^4.0.1"
+ }
+ },
+ "node_modules/remark/node_modules/is-buffer": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
+ "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/remark/node_modules/remark-parse": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-6.0.3.tgz",
+ "integrity": "sha512-QbDXWN4HfKTUC0hHa4teU463KclLAnwpn/FBn87j9cKYJWWawbiLgMfP2Q4XwhxxuuuOxHlw+pSN0OKuJwyVvg==",
+ "dev": true,
+ "dependencies": {
+ "collapse-white-space": "^1.0.2",
+ "is-alphabetical": "^1.0.0",
+ "is-decimal": "^1.0.0",
+ "is-whitespace-character": "^1.0.0",
+ "is-word-character": "^1.0.0",
+ "markdown-escapes": "^1.0.0",
+ "parse-entities": "^1.1.0",
+ "repeat-string": "^1.5.4",
+ "state-toggle": "^1.0.0",
+ "trim": "0.0.1",
+ "trim-trailing-lines": "^1.0.0",
+ "unherit": "^1.0.4",
+ "unist-util-remove-position": "^1.0.0",
+ "vfile-location": "^2.0.0",
+ "xtend": "^4.0.1"
+ }
+ },
+ "node_modules/remark/node_modules/unified": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/unified/-/unified-7.1.0.tgz",
+ "integrity": "sha512-lbk82UOIGuCEsZhPj8rNAkXSDXd6p0QLzIuSsCdxrqnqU56St4eyOB+AlXsVgVeRmetPTYydIuvFfpDIed8mqw==",
+ "dev": true,
+ "dependencies": {
+ "@types/unist": "^2.0.0",
+ "@types/vfile": "^3.0.0",
+ "bail": "^1.0.0",
+ "extend": "^3.0.0",
+ "is-plain-obj": "^1.1.0",
+ "trough": "^1.0.0",
+ "vfile": "^3.0.0",
+ "x-is-string": "^0.1.0"
+ }
+ },
+ "node_modules/remark/node_modules/vfile": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/vfile/-/vfile-3.0.1.tgz",
+ "integrity": "sha512-y7Y3gH9BsUSdD4KzHsuMaCzRjglXN0W2EcMf0gpvu6+SbsGhMje7xDc8AEoeXy6mIwCKMI6BkjMsRjzQbhMEjQ==",
+ "dev": true,
+ "dependencies": {
+ "is-buffer": "^2.0.0",
+ "replace-ext": "1.0.0",
+ "unist-util-stringify-position": "^1.0.0",
+ "vfile-message": "^1.0.0"
+ }
+ },
+ "node_modules/remove-trailing-separator": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+ "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
+ "dev": true,
+ "optional": true
+ },
+ "node_modules/repeat-element": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
+ "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/repeat-string": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/repeating": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
+ "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
+ "dev": true,
+ "dependencies": {
+ "is-finite": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/replace-ext": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz",
+ "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/request": {
+ "version": "2.88.2",
+ "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
+ "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
+ "dev": true,
+ "dependencies": {
+ "aws-sign2": "~0.7.0",
+ "aws4": "^1.8.0",
+ "caseless": "~0.12.0",
+ "combined-stream": "~1.0.6",
+ "extend": "~3.0.2",
+ "forever-agent": "~0.6.1",
+ "form-data": "~2.3.2",
+ "har-validator": "~5.1.3",
+ "http-signature": "~1.2.0",
+ "is-typedarray": "~1.0.0",
+ "isstream": "~0.1.2",
+ "json-stringify-safe": "~5.0.1",
+ "mime-types": "~2.1.19",
+ "oauth-sign": "~0.9.0",
+ "performance-now": "^2.1.0",
+ "qs": "~6.5.2",
+ "safe-buffer": "^5.1.2",
+ "tough-cookie": "~2.5.0",
+ "tunnel-agent": "^0.6.0",
+ "uuid": "^3.3.2"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/request/node_modules/qs": {
+ "version": "6.5.2",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
+ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/require-main-filename": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
+ "dev": true
+ },
+ "node_modules/resolve": {
+ "version": "1.19.0",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz",
+ "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==",
+ "dev": true,
+ "dependencies": {
+ "is-core-module": "^2.1.0",
+ "path-parse": "^1.0.6"
+ }
+ },
+ "node_modules/resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/resolve-url": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
+ "dev": true
+ },
+ "node_modules/restore-cursor": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
+ "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
+ "dev": true,
+ "dependencies": {
+ "onetime": "^2.0.0",
+ "signal-exit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/ret": {
+ "version": "0.1.15",
+ "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/rimraf": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
+ "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
+ "dev": true,
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ }
+ },
+ "node_modules/rtlcss": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-2.6.1.tgz",
+ "integrity": "sha512-WoKAYLxT123Gh/9dAPeMY0YWBx6D7IjORJhTbmmq8UJI4zaSxsA0uqPWsXEqGgZT2HEGtxWkhkIZ6g1IvOQ+eg==",
+ "dev": true,
+ "dependencies": {
+ "@choojs/findup": "^0.2.1",
+ "chalk": "^2.4.2",
+ "mkdirp": "^0.5.1",
+ "postcss": "^6.0.23",
+ "strip-json-comments": "^2.0.0"
+ },
+ "bin": {
+ "rtlcss": "bin/rtlcss.js"
+ }
+ },
+ "node_modules/rtlcss/node_modules/postcss": {
+ "version": "6.0.23",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
+ "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.4.1",
+ "source-map": "^0.6.1",
+ "supports-color": "^5.4.0"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/rtlcss/node_modules/strip-json-comments": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/run-async": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
+ "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/rx-lite": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz",
+ "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=",
+ "dev": true
+ },
+ "node_modules/rxjs": {
+ "version": "6.6.3",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz",
+ "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==",
+ "dev": true,
+ "dependencies": {
+ "tslib": "^1.9.0"
+ },
+ "engines": {
+ "npm": ">=2.0.0"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "node_modules/safe-json-parse": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz",
+ "integrity": "sha1-PnZyPjjf3aE8mx0poeB//uSzC1c=",
+ "dev": true
+ },
+ "node_modules/safe-regex": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+ "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
+ "dev": true,
+ "dependencies": {
+ "ret": "~0.1.10"
+ }
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "dev": true
+ },
+ "node_modules/sass-graph": {
+ "version": "2.2.5",
+ "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.5.tgz",
+ "integrity": "sha512-VFWDAHOe6mRuT4mZRd4eKE+d8Uedrk6Xnh7Sh9b4NGufQLQjOrvf/MQoOdx+0s92L89FeyUUNfU597j/3uNpag==",
+ "dev": true,
+ "dependencies": {
+ "glob": "^7.0.0",
+ "lodash": "^4.0.0",
+ "scss-tokenizer": "^0.2.3",
+ "yargs": "^13.3.2"
+ }
+ },
+ "node_modules/sass-graph/node_modules/ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/sass-graph/node_modules/camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/sass-graph/node_modules/cliui": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
+ "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
+ "dev": true,
+ "dependencies": {
+ "string-width": "^3.1.0",
+ "strip-ansi": "^5.2.0",
+ "wrap-ansi": "^5.1.0"
+ }
+ },
+ "node_modules/sass-graph/node_modules/find-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/sass-graph/node_modules/string-width": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+ "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+ "dev": true,
+ "dependencies": {
+ "emoji-regex": "^7.0.1",
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/sass-graph/node_modules/strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/sass-graph/node_modules/wrap-ansi": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
+ "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^3.2.0",
+ "string-width": "^3.0.0",
+ "strip-ansi": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/sass-graph/node_modules/yargs": {
+ "version": "13.3.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
+ "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
+ "dev": true,
+ "dependencies": {
+ "cliui": "^5.0.0",
+ "find-up": "^3.0.0",
+ "get-caller-file": "^2.0.1",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^2.0.0",
+ "set-blocking": "^2.0.0",
+ "string-width": "^3.0.0",
+ "which-module": "^2.0.0",
+ "y18n": "^4.0.0",
+ "yargs-parser": "^13.1.2"
+ }
+ },
+ "node_modules/sass-graph/node_modules/yargs-parser": {
+ "version": "13.1.2",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
+ "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
+ "dev": true,
+ "dependencies": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
+ }
+ },
+ "node_modules/scss-tokenizer": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz",
+ "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=",
+ "dev": true,
+ "dependencies": {
+ "js-base64": "^2.1.8",
+ "source-map": "^0.4.2"
+ }
+ },
+ "node_modules/scss-tokenizer/node_modules/source-map": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
+ "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
+ "dev": true,
+ "dependencies": {
+ "amdefine": ">=0.0.4"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver"
+ }
+ },
+ "node_modules/set-blocking": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
+ "dev": true
+ },
+ "node_modules/set-value": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
+ "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
+ "dev": true,
+ "dependencies": {
+ "extend-shallow": "^2.0.1",
+ "is-extendable": "^0.1.1",
+ "is-plain-object": "^2.0.3",
+ "split-string": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/set-value/node_modules/extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "dependencies": {
+ "is-extendable": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/shebang-command": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+ "dev": true,
+ "dependencies": {
+ "shebang-regex": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/shelljs": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz",
+ "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=",
+ "dev": true,
+ "bin": {
+ "shjs": "bin/shjs"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/sigmund": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz",
+ "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=",
+ "dev": true
+ },
+ "node_modules/signal-exit": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
+ "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
+ "dev": true
+ },
+ "node_modules/slash": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
+ "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/slice-ansi": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz",
+ "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^3.2.0",
+ "astral-regex": "^1.0.0",
+ "is-fullwidth-code-point": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/snapdragon": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
+ "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
+ "dev": true,
+ "dependencies": {
+ "base": "^0.11.1",
+ "debug": "^2.2.0",
+ "define-property": "^0.2.5",
+ "extend-shallow": "^2.0.1",
+ "map-cache": "^0.2.2",
+ "source-map": "^0.5.6",
+ "source-map-resolve": "^0.5.0",
+ "use": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/snapdragon-node": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
+ "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
+ "dev": true,
+ "dependencies": {
+ "define-property": "^1.0.0",
+ "isobject": "^3.0.0",
+ "snapdragon-util": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/snapdragon-node/node_modules/define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "dev": true,
+ "dependencies": {
+ "is-descriptor": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/snapdragon-node/node_modules/is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/snapdragon-node/node_modules/is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/snapdragon-node/node_modules/is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "dependencies": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/snapdragon-node/node_modules/isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/snapdragon-node/node_modules/kind-of": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/snapdragon-util": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
+ "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^3.2.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/snapdragon/node_modules/define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "dependencies": {
+ "is-descriptor": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/snapdragon/node_modules/extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "dependencies": {
+ "is-extendable": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/snapdragon/node_modules/source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map-resolve": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
+ "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==",
+ "dev": true,
+ "dependencies": {
+ "atob": "^2.1.2",
+ "decode-uri-component": "^0.2.0",
+ "resolve-url": "^0.2.1",
+ "source-map-url": "^0.4.0",
+ "urix": "^0.1.0"
+ }
+ },
+ "node_modules/source-map-support": {
+ "version": "0.4.18",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz",
+ "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==",
+ "dev": true,
+ "dependencies": {
+ "source-map": "^0.5.6"
+ }
+ },
+ "node_modules/source-map-support/node_modules/source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map-url": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
+ "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
+ "dev": true
+ },
+ "node_modules/spdx-correct": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
+ "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==",
+ "dev": true,
+ "dependencies": {
+ "spdx-expression-parse": "^3.0.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "node_modules/spdx-exceptions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
+ "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
+ "dev": true
+ },
+ "node_modules/spdx-expression-parse": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
+ "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
+ "dev": true,
+ "dependencies": {
+ "spdx-exceptions": "^2.1.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "node_modules/spdx-license-ids": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz",
+ "integrity": "sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==",
+ "dev": true
+ },
+ "node_modules/specificity": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/specificity/-/specificity-0.4.1.tgz",
+ "integrity": "sha512-1klA3Gi5PD1Wv9Q0wUoOQN1IWAuPu0D1U03ThXTr0cJ20+/iq2tHSDnK7Kk/0LXJ1ztUB2/1Os0wKmfyNgUQfg==",
+ "dev": true,
+ "bin": {
+ "specificity": "bin/specificity"
+ }
+ },
+ "node_modules/spectre.css": {
+ "version": "0.5.9",
+ "resolved": "https://registry.npmjs.org/spectre.css/-/spectre.css-0.5.9.tgz",
+ "integrity": "sha512-9jUqwZmCnvflrxFGcK+ize43TvjwDjqMwZPVubEtSIHzvinH0TBUESm1LcOJx3Ur7bdPaeOHQIjOqBl1Y5kLFw==",
+ "dev": true
+ },
+ "node_modules/split-string": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
+ "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
+ "dev": true,
+ "dependencies": {
+ "extend-shallow": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
+ "dev": true
+ },
+ "node_modules/sshpk": {
+ "version": "1.16.1",
+ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
+ "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
+ "dev": true,
+ "dependencies": {
+ "asn1": "~0.2.3",
+ "assert-plus": "^1.0.0",
+ "bcrypt-pbkdf": "^1.0.0",
+ "dashdash": "^1.12.0",
+ "ecc-jsbn": "~0.1.1",
+ "getpass": "^0.1.1",
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.0.2",
+ "tweetnacl": "~0.14.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/state-toggle": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz",
+ "integrity": "sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==",
+ "dev": true
+ },
+ "node_modules/static-extend": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
+ "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
+ "dev": true,
+ "dependencies": {
+ "define-property": "^0.2.5",
+ "object-copy": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/static-extend/node_modules/define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "dependencies": {
+ "is-descriptor": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/stdout-stream": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz",
+ "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==",
+ "dev": true,
+ "dependencies": {
+ "readable-stream": "^2.0.1"
+ }
+ },
+ "node_modules/string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "node_modules/string-template": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz",
+ "integrity": "sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=",
+ "dev": true
+ },
+ "node_modules/string-width": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+ "dev": true,
+ "dependencies": {
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/string-width/node_modules/ansi-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/string-width/node_modules/strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/string.prototype.trimend": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.2.tgz",
+ "integrity": "sha512-8oAG/hi14Z4nOVP0z6mdiVZ/wqjDtWSLygMigTzAb+7aPEDTleeFf+WrF+alzecxIRkckkJVn+dTlwzJXORATw==",
+ "dev": true,
+ "dependencies": {
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.18.0-next.1"
+ }
+ },
+ "node_modules/string.prototype.trimend/node_modules/es-abstract": {
+ "version": "1.18.0-next.1",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz",
+ "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==",
+ "dev": true,
+ "dependencies": {
+ "es-to-primitive": "^1.2.1",
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1",
+ "is-callable": "^1.2.2",
+ "is-negative-zero": "^2.0.0",
+ "is-regex": "^1.1.1",
+ "object-inspect": "^1.8.0",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.1",
+ "string.prototype.trimend": "^1.0.1",
+ "string.prototype.trimstart": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/string.prototype.trimend/node_modules/object.assign": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
+ "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3",
+ "has-symbols": "^1.0.1",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/string.prototype.trimstart": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.2.tgz",
+ "integrity": "sha512-7F6CdBTl5zyu30BJFdzSTlSlLPwODC23Od+iLoVH8X6+3fvDPPuBVVj9iaB1GOsSTSIgVfsfm27R2FGrAPznWg==",
+ "dev": true,
+ "dependencies": {
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.18.0-next.1"
+ }
+ },
+ "node_modules/string.prototype.trimstart/node_modules/es-abstract": {
+ "version": "1.18.0-next.1",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz",
+ "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==",
+ "dev": true,
+ "dependencies": {
+ "es-to-primitive": "^1.2.1",
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1",
+ "is-callable": "^1.2.2",
+ "is-negative-zero": "^2.0.0",
+ "is-regex": "^1.1.1",
+ "object-inspect": "^1.8.0",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.1",
+ "string.prototype.trimend": "^1.0.1",
+ "string.prototype.trimstart": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/string.prototype.trimstart/node_modules/object.assign": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
+ "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3",
+ "has-symbols": "^1.0.1",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/stringify-entities": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-1.3.2.tgz",
+ "integrity": "sha512-nrBAQClJAPN2p+uGCVJRPIPakKeKWZ9GtBCmormE7pWOSlHat7+x5A8gx85M7HM5Dt0BP3pP5RhVW77WdbJJ3A==",
+ "dev": true,
+ "dependencies": {
+ "character-entities-html4": "^1.0.0",
+ "character-entities-legacy": "^1.0.0",
+ "is-alphanumerical": "^1.0.0",
+ "is-hexadecimal": "^1.0.0"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/strip-bom": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
+ "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
+ "dev": true,
+ "dependencies": {
+ "is-utf8": "^0.2.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/strip-eof": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
+ "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/strip-indent": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz",
+ "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=",
+ "dev": true,
+ "dependencies": {
+ "get-stdin": "^4.0.1"
+ },
+ "bin": {
+ "strip-indent": "cli.js"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/style-search": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz",
+ "integrity": "sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI=",
+ "dev": true
+ },
+ "node_modules/stylelint": {
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-10.1.0.tgz",
+ "integrity": "sha512-OmlUXrgzEMLQYj1JPTpyZPR9G4bl0StidfHnGJEMpdiQ0JyTq0MPg1xkHk1/xVJ2rTPESyJCDWjG8Kbpoo7Kuw==",
+ "dev": true,
+ "dependencies": {
+ "autoprefixer": "^9.5.1",
+ "balanced-match": "^1.0.0",
+ "chalk": "^2.4.2",
+ "cosmiconfig": "^5.2.0",
+ "debug": "^4.1.1",
+ "execall": "^2.0.0",
+ "file-entry-cache": "^5.0.1",
+ "get-stdin": "^7.0.0",
+ "global-modules": "^2.0.0",
+ "globby": "^9.2.0",
+ "globjoin": "^0.1.4",
+ "html-tags": "^3.0.0",
+ "ignore": "^5.0.6",
+ "import-lazy": "^4.0.0",
+ "imurmurhash": "^0.1.4",
+ "known-css-properties": "^0.14.0",
+ "leven": "^3.1.0",
+ "lodash": "^4.17.11",
+ "log-symbols": "^3.0.0",
+ "mathml-tag-names": "^2.1.0",
+ "meow": "^5.0.0",
+ "micromatch": "^4.0.0",
+ "normalize-selector": "^0.2.0",
+ "pify": "^4.0.1",
+ "postcss": "^7.0.14",
+ "postcss-html": "^0.36.0",
+ "postcss-jsx": "^0.36.1",
+ "postcss-less": "^3.1.4",
+ "postcss-markdown": "^0.36.0",
+ "postcss-media-query-parser": "^0.2.3",
+ "postcss-reporter": "^6.0.1",
+ "postcss-resolve-nested-selector": "^0.1.1",
+ "postcss-safe-parser": "^4.0.1",
+ "postcss-sass": "^0.3.5",
+ "postcss-scss": "^2.0.0",
+ "postcss-selector-parser": "^3.1.0",
+ "postcss-syntax": "^0.36.2",
+ "postcss-value-parser": "^3.3.1",
+ "resolve-from": "^5.0.0",
+ "signal-exit": "^3.0.2",
+ "slash": "^3.0.0",
+ "specificity": "^0.4.1",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^5.2.0",
+ "style-search": "^0.1.0",
+ "sugarss": "^2.0.0",
+ "svg-tags": "^1.0.0",
+ "table": "^5.2.3"
+ },
+ "bin": {
+ "stylelint": "bin/stylelint.js"
+ },
+ "engines": {
+ "node": ">=8.7.0"
+ }
+ },
+ "node_modules/stylelint-config-recommended": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-2.2.0.tgz",
+ "integrity": "sha512-bZ+d4RiNEfmoR74KZtCKmsABdBJr4iXRiCso+6LtMJPw5rd/KnxUWTxht7TbafrTJK1YRjNgnN0iVZaJfc3xJA==",
+ "dev": true
+ },
+ "node_modules/stylelint-config-recommended-scss": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-3.3.0.tgz",
+ "integrity": "sha512-BvuuLYwoet8JutOP7K1a8YaiENN+0HQn390eDi0SWe1h7Uhx6O3GUQ6Ubgie9b/AmHX4Btmp+ZzVGbzriFTBcA==",
+ "dev": true,
+ "dependencies": {
+ "stylelint-config-recommended": "^2.2.0"
+ }
+ },
+ "node_modules/stylelint-config-wordpress": {
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/stylelint-config-wordpress/-/stylelint-config-wordpress-14.0.0.tgz",
+ "integrity": "sha512-Qo5I9Qa3yOy2AF+DwL9wjdNSm10ykT4lM+JvnCMDT2VBOl+5yMgpbQ9Xaa0gQXeCdcHdLprtmkBbrvDqf6DWSg==",
+ "dev": true,
+ "dependencies": {
+ "stylelint-config-recommended": "^2.2.0",
+ "stylelint-config-recommended-scss": "^3.2.0",
+ "stylelint-scss": "^3.6.0"
+ },
+ "engines": {
+ "node": ">=8.9.3"
+ }
+ },
+ "node_modules/stylelint-scss": {
+ "version": "3.18.0",
+ "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-3.18.0.tgz",
+ "integrity": "sha512-LD7+hv/6/ApNGt7+nR/50ft7cezKP2HM5rI8avIdGaUWre3xlHfV4jKO/DRZhscfuN+Ewy9FMhcTq0CcS0C/SA==",
+ "dev": true,
+ "dependencies": {
+ "lodash": "^4.17.15",
+ "postcss-media-query-parser": "^0.2.3",
+ "postcss-resolve-nested-selector": "^0.1.1",
+ "postcss-selector-parser": "^6.0.2",
+ "postcss-value-parser": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/stylelint-scss/node_modules/postcss-selector-parser": {
+ "version": "6.0.4",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.4.tgz",
+ "integrity": "sha512-gjMeXBempyInaBqpp8gODmwZ52WaYsVOsfr4L4lDQ7n3ncD6mEyySiDtgzCT+NYC0mmeOLvtsF8iaEf0YT6dBw==",
+ "dev": true,
+ "dependencies": {
+ "cssesc": "^3.0.0",
+ "indexes-of": "^1.0.1",
+ "uniq": "^1.0.1",
+ "util-deprecate": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/stylelint/node_modules/ansi-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/stylelint/node_modules/braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dev": true,
+ "dependencies": {
+ "fill-range": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/stylelint/node_modules/camelcase": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
+ "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/stylelint/node_modules/camelcase-keys": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-4.2.0.tgz",
+ "integrity": "sha1-oqpfsa9oh1glnDLBQUJteJI7m3c=",
+ "dev": true,
+ "dependencies": {
+ "camelcase": "^4.1.0",
+ "map-obj": "^2.0.0",
+ "quick-lru": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/stylelint/node_modules/cosmiconfig": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
+ "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==",
+ "dev": true,
+ "dependencies": {
+ "import-fresh": "^2.0.0",
+ "is-directory": "^0.3.1",
+ "js-yaml": "^3.13.1",
+ "parse-json": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/stylelint/node_modules/debug": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz",
+ "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ }
+ },
+ "node_modules/stylelint/node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "node_modules/stylelint/node_modules/fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/stylelint/node_modules/find-up": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
+ "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/stylelint/node_modules/get-stdin": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz",
+ "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/stylelint/node_modules/globby": {
+ "version": "9.2.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-9.2.0.tgz",
+ "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==",
+ "dev": true,
+ "dependencies": {
+ "@types/glob": "^7.1.1",
+ "array-union": "^1.0.2",
+ "dir-glob": "^2.2.2",
+ "fast-glob": "^2.2.6",
+ "glob": "^7.1.3",
+ "ignore": "^4.0.3",
+ "pify": "^4.0.1",
+ "slash": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/stylelint/node_modules/globby/node_modules/ignore": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
+ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/stylelint/node_modules/globby/node_modules/slash": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
+ "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/stylelint/node_modules/ignore": {
+ "version": "5.1.8",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz",
+ "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/stylelint/node_modules/import-fresh": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
+ "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=",
+ "dev": true,
+ "dependencies": {
+ "caller-path": "^2.0.0",
+ "resolve-from": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/stylelint/node_modules/import-fresh/node_modules/resolve-from": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
+ "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/stylelint/node_modules/indent-string": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz",
+ "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/stylelint/node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/stylelint/node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/stylelint/node_modules/leven": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
+ "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/stylelint/node_modules/load-json-file": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
+ "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=",
+ "dev": true,
+ "dependencies": {
+ "graceful-fs": "^4.1.2",
+ "parse-json": "^4.0.0",
+ "pify": "^3.0.0",
+ "strip-bom": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/stylelint/node_modules/load-json-file/node_modules/pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/stylelint/node_modules/locate-path": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
+ "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^2.0.0",
+ "path-exists": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/stylelint/node_modules/log-symbols": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz",
+ "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.4.2"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/stylelint/node_modules/map-obj": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz",
+ "integrity": "sha1-plzSkIepJZi4eRJXpSPgISIqwfk=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/stylelint/node_modules/meow": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/meow/-/meow-5.0.0.tgz",
+ "integrity": "sha512-CbTqYU17ABaLefO8vCU153ZZlprKYWDljcndKKDCFcYQITzWCXZAVk4QMFZPgvzrnUQ3uItnIE/LoUOwrT15Ig==",
+ "dev": true,
+ "dependencies": {
+ "camelcase-keys": "^4.0.0",
+ "decamelize-keys": "^1.0.0",
+ "loud-rejection": "^1.0.0",
+ "minimist-options": "^3.0.1",
+ "normalize-package-data": "^2.3.4",
+ "read-pkg-up": "^3.0.0",
+ "redent": "^2.0.0",
+ "trim-newlines": "^2.0.0",
+ "yargs-parser": "^10.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/stylelint/node_modules/micromatch": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
+ "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
+ "dev": true,
+ "dependencies": {
+ "braces": "^3.0.1",
+ "picomatch": "^2.0.5"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/stylelint/node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "node_modules/stylelint/node_modules/p-limit": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
+ "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
+ "dev": true,
+ "dependencies": {
+ "p-try": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/stylelint/node_modules/p-locate": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
+ "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/stylelint/node_modules/p-try": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
+ "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/stylelint/node_modules/parse-json": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
+ "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
+ "dev": true,
+ "dependencies": {
+ "error-ex": "^1.3.1",
+ "json-parse-better-errors": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/stylelint/node_modules/path-exists": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+ "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/stylelint/node_modules/path-type": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
+ "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
+ "dev": true,
+ "dependencies": {
+ "pify": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/stylelint/node_modules/path-type/node_modules/pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/stylelint/node_modules/pify": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
+ "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/stylelint/node_modules/postcss-less": {
+ "version": "3.1.4",
+ "resolved": "https://registry.npmjs.org/postcss-less/-/postcss-less-3.1.4.tgz",
+ "integrity": "sha512-7TvleQWNM2QLcHqvudt3VYjULVB49uiW6XzEUFmvwHzvsOEF5MwBrIXZDJQvJNFGjJQTzSzZnDoCJ8h/ljyGXA==",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^7.0.14"
+ },
+ "engines": {
+ "node": ">=6.14.4"
+ }
+ },
+ "node_modules/stylelint/node_modules/postcss-scss": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-2.1.1.tgz",
+ "integrity": "sha512-jQmGnj0hSGLd9RscFw9LyuSVAa5Bl1/KBPqG1NQw9w8ND55nY4ZEsdlVuYJvLPpV+y0nwTV5v/4rHPzZRihQbA==",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^7.0.6"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/stylelint/node_modules/postcss-selector-parser": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz",
+ "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==",
+ "dev": true,
+ "dependencies": {
+ "dot-prop": "^5.2.0",
+ "indexes-of": "^1.0.1",
+ "uniq": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/stylelint/node_modules/postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ },
+ "node_modules/stylelint/node_modules/read-pkg": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
+ "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=",
+ "dev": true,
+ "dependencies": {
+ "load-json-file": "^4.0.0",
+ "normalize-package-data": "^2.3.2",
+ "path-type": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/stylelint/node_modules/read-pkg-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz",
+ "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=",
+ "dev": true,
+ "dependencies": {
+ "find-up": "^2.0.0",
+ "read-pkg": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/stylelint/node_modules/redent": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/redent/-/redent-2.0.0.tgz",
+ "integrity": "sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo=",
+ "dev": true,
+ "dependencies": {
+ "indent-string": "^3.0.0",
+ "strip-indent": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/stylelint/node_modules/resolve-from": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/stylelint/node_modules/slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/stylelint/node_modules/string-width": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+ "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+ "dev": true,
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/stylelint/node_modules/string-width/node_modules/strip-ansi": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/stylelint/node_modules/strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/stylelint/node_modules/strip-ansi/node_modules/ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/stylelint/node_modules/strip-bom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+ "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/stylelint/node_modules/strip-indent": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz",
+ "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/stylelint/node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/stylelint/node_modules/trim-newlines": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-2.0.0.tgz",
+ "integrity": "sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/stylelint/node_modules/yargs-parser": {
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz",
+ "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==",
+ "dev": true,
+ "dependencies": {
+ "camelcase": "^4.1.0"
+ }
+ },
+ "node_modules/sugarss": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/sugarss/-/sugarss-2.0.0.tgz",
+ "integrity": "sha512-WfxjozUk0UVA4jm+U1d736AUpzSrNsQcIbyOkoE364GrtWmIrFdk5lksEupgWMD4VaT/0kVx1dobpiDumSgmJQ==",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^7.0.2"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/svg-tags": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz",
+ "integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=",
+ "dev": true
+ },
+ "node_modules/table": {
+ "version": "5.4.6",
+ "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz",
+ "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==",
+ "dev": true,
+ "dependencies": {
+ "ajv": "^6.10.2",
+ "lodash": "^4.17.14",
+ "slice-ansi": "^2.1.0",
+ "string-width": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/table/node_modules/ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/table/node_modules/string-width": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+ "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+ "dev": true,
+ "dependencies": {
+ "emoji-regex": "^7.0.1",
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/table/node_modules/strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/tar": {
+ "version": "6.0.5",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-6.0.5.tgz",
+ "integrity": "sha512-0b4HOimQHj9nXNEAA7zWwMM91Zhhba3pspja6sQbgTpynOJf+bkjBnfybNYzbpLbnwXnbyB4LOREvlyXLkCHSg==",
+ "dev": true,
+ "dependencies": {
+ "chownr": "^2.0.0",
+ "fs-minipass": "^2.0.0",
+ "minipass": "^3.0.0",
+ "minizlib": "^2.1.1",
+ "mkdirp": "^1.0.3",
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/tar/node_modules/mkdirp": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+ "dev": true,
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
+ "dev": true
+ },
+ "node_modules/through": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
+ "dev": true
+ },
+ "node_modules/tiny-lr": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.1.1.tgz",
+ "integrity": "sha512-44yhA3tsaRoMOjQQ+5v5mVdqef+kH6Qze9jTpqtVufgYjYt08zyZAwNwwVBj3i1rJMnR52IxOW0LK0vBzgAkuA==",
+ "dev": true,
+ "dependencies": {
+ "body": "^5.1.0",
+ "debug": "^3.1.0",
+ "faye-websocket": "~0.10.0",
+ "livereload-js": "^2.3.0",
+ "object-assign": "^4.1.0",
+ "qs": "^6.4.0"
+ }
+ },
+ "node_modules/tiny-lr/node_modules/debug": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+ "dev": true,
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
+ "node_modules/tiny-lr/node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "node_modules/tmp": {
+ "version": "0.0.33",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+ "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+ "dev": true,
+ "dependencies": {
+ "os-tmpdir": "~1.0.2"
+ },
+ "engines": {
+ "node": ">=0.6.0"
+ }
+ },
+ "node_modules/to-fast-properties": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz",
+ "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/to-object-path": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
+ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/to-regex": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+ "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
+ "dev": true,
+ "dependencies": {
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "regex-not": "^1.0.2",
+ "safe-regex": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
+ "dev": true,
+ "dependencies": {
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/to-regex-range/node_modules/is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/tough-cookie": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
+ "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
+ "dev": true,
+ "dependencies": {
+ "psl": "^1.1.28",
+ "punycode": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/trim": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz",
+ "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0=",
+ "dev": true
+ },
+ "node_modules/trim-newlines": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
+ "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/trim-right": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
+ "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/trim-trailing-lines": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.4.tgz",
+ "integrity": "sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ==",
+ "dev": true
+ },
+ "node_modules/trough": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz",
+ "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==",
+ "dev": true
+ },
+ "node_modules/true-case-path": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz",
+ "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==",
+ "dev": true,
+ "dependencies": {
+ "glob": "^7.1.2"
+ }
+ },
+ "node_modules/tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+ "dev": true
+ },
+ "node_modules/tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/tweetnacl": {
+ "version": "0.14.5",
+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
+ "dev": true
+ },
+ "node_modules/type-check": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+ "dev": true,
+ "dependencies": {
+ "prelude-ls": "~1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/type-detect": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
+ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.6.2.tgz",
+ "integrity": "sha1-PFtv1/beCRQmkCfwPAlGdY92c6Q=",
+ "dev": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=4.2.0"
+ }
+ },
+ "node_modules/typescript-eslint-parser": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/typescript-eslint-parser/-/typescript-eslint-parser-9.0.1.tgz",
+ "integrity": "sha512-w1jqotvnhLtLukD9H3gQPAlbD0kLf7ZkoQGwiwSIshKIlzRL7i0OY9Y7VIdE1xtytZXThg678eomxMZ1rZXGVQ==",
+ "dev": true,
+ "dependencies": {
+ "lodash.unescape": "4.0.1",
+ "semver": "5.4.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/typescript-eslint-parser/node_modules/semver": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
+ "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver"
+ }
+ },
+ "node_modules/uglify-js": {
+ "version": "3.11.5",
+ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.11.5.tgz",
+ "integrity": "sha512-btvv/baMqe7HxP7zJSF7Uc16h1mSfuuSplT0/qdjxseesDU+yYzH33eHBH+eMdeRXwujXspaCTooWHQVVBh09w==",
+ "dev": true,
+ "bin": {
+ "uglifyjs": "bin/uglifyjs"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/underscore.string": {
+ "version": "3.3.5",
+ "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.5.tgz",
+ "integrity": "sha512-g+dpmgn+XBneLmXXo+sGlW5xQEt4ErkS3mgeN2GFbremYeMBSJKr9Wf2KJplQVaiPY/f7FN6atosWYNm9ovrYg==",
+ "dev": true,
+ "dependencies": {
+ "sprintf-js": "^1.0.3",
+ "util-deprecate": "^1.0.2"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/unherit": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz",
+ "integrity": "sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.0",
+ "xtend": "^4.0.0"
+ }
+ },
+ "node_modules/unicode-regex": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/unicode-regex/-/unicode-regex-1.0.1.tgz",
+ "integrity": "sha1-+BngUBkdW5VhozmljdO5CV7ZSzU=",
+ "dev": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/unified": {
+ "version": "6.1.6",
+ "resolved": "https://registry.npmjs.org/unified/-/unified-6.1.6.tgz",
+ "integrity": "sha512-pW2f82bCIo2ifuIGYcV12fL96kMMYgw7JKVEgh7ODlrM9rj6vXSY3BV+H6lCcv1ksxynFf582hwWLnA1qRFy4w==",
+ "dev": true,
+ "dependencies": {
+ "bail": "^1.0.0",
+ "extend": "^3.0.0",
+ "is-plain-obj": "^1.1.0",
+ "trough": "^1.0.0",
+ "vfile": "^2.0.0",
+ "x-is-function": "^1.0.4",
+ "x-is-string": "^0.1.0"
+ }
+ },
+ "node_modules/union-value": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
+ "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
+ "dev": true,
+ "dependencies": {
+ "arr-union": "^3.1.0",
+ "get-value": "^2.0.6",
+ "is-extendable": "^0.1.1",
+ "set-value": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/uniq": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
+ "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=",
+ "dev": true
+ },
+ "node_modules/unist-util-find-all-after": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/unist-util-find-all-after/-/unist-util-find-all-after-1.0.5.tgz",
+ "integrity": "sha512-lWgIc3rrTMTlK1Y0hEuL+k+ApzFk78h+lsaa2gHf63Gp5Ww+mt11huDniuaoq1H+XMK2lIIjjPkncxXcDp3QDw==",
+ "dev": true,
+ "dependencies": {
+ "unist-util-is": "^3.0.0"
+ }
+ },
+ "node_modules/unist-util-is": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-3.0.0.tgz",
+ "integrity": "sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A==",
+ "dev": true
+ },
+ "node_modules/unist-util-remove-position": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-1.1.4.tgz",
+ "integrity": "sha512-tLqd653ArxJIPnKII6LMZwH+mb5q+n/GtXQZo6S6csPRs5zB0u79Yw8ouR3wTw8wxvdJFhpP6Y7jorWdCgLO0A==",
+ "dev": true,
+ "dependencies": {
+ "unist-util-visit": "^1.1.0"
+ }
+ },
+ "node_modules/unist-util-stringify-position": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz",
+ "integrity": "sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ==",
+ "dev": true
+ },
+ "node_modules/unist-util-visit": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-1.4.1.tgz",
+ "integrity": "sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw==",
+ "dev": true,
+ "dependencies": {
+ "unist-util-visit-parents": "^2.0.0"
+ }
+ },
+ "node_modules/unist-util-visit-parents": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz",
+ "integrity": "sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g==",
+ "dev": true,
+ "dependencies": {
+ "unist-util-is": "^3.0.0"
+ }
+ },
+ "node_modules/unset-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
+ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
+ "dev": true,
+ "dependencies": {
+ "has-value": "^0.3.1",
+ "isobject": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/unset-value/node_modules/has-value": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
+ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
+ "dev": true,
+ "dependencies": {
+ "get-value": "^2.0.3",
+ "has-values": "^0.1.4",
+ "isobject": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/unset-value/node_modules/has-value/node_modules/isobject": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+ "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+ "dev": true,
+ "dependencies": {
+ "isarray": "1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/unset-value/node_modules/has-values": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
+ "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/unset-value/node_modules/isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/upath": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz",
+ "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==",
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": ">=4",
+ "yarn": "*"
+ }
+ },
+ "node_modules/uri-js": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz",
+ "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==",
+ "dev": true,
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/uri-path": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/uri-path/-/uri-path-1.0.0.tgz",
+ "integrity": "sha1-l0fwGDWJM8Md4PzP2C0TjmcmLjI=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/urix": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
+ "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
+ "dev": true
+ },
+ "node_modules/use": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
+ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/user-home": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz",
+ "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=",
+ "dev": true,
+ "bin": {
+ "user-home": "cli.js"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+ "dev": true
+ },
+ "node_modules/uuid": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
+ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
+ "dev": true,
+ "bin": {
+ "uuid": "bin/uuid"
+ }
+ },
+ "node_modules/v8-compile-cache": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz",
+ "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==",
+ "dev": true
+ },
+ "node_modules/v8flags": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.1.1.tgz",
+ "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=",
+ "dev": true,
+ "dependencies": {
+ "user-home": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/validate-npm-package-license": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+ "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+ "dev": true,
+ "dependencies": {
+ "spdx-correct": "^3.0.0",
+ "spdx-expression-parse": "^3.0.0"
+ }
+ },
+ "node_modules/verror": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+ "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+ "dev": true,
+ "engines": [
+ "node >=0.6.0"
+ ],
+ "dependencies": {
+ "assert-plus": "^1.0.0",
+ "core-util-is": "1.0.2",
+ "extsprintf": "^1.2.0"
+ }
+ },
+ "node_modules/vfile": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/vfile/-/vfile-2.3.0.tgz",
+ "integrity": "sha512-ASt4mBUHcTpMKD/l5Q+WJXNtshlWxOogYyGYYrg4lt/vuRjC1EFQtlAofL5VmtVNIZJzWYFJjzGWZ0Gw8pzW1w==",
+ "dev": true,
+ "dependencies": {
+ "is-buffer": "^1.1.4",
+ "replace-ext": "1.0.0",
+ "unist-util-stringify-position": "^1.0.0",
+ "vfile-message": "^1.0.0"
+ }
+ },
+ "node_modules/vfile-location": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-2.0.6.tgz",
+ "integrity": "sha512-sSFdyCP3G6Ka0CEmN83A2YCMKIieHx0EDaj5IDP4g1pa5ZJ4FJDvpO0WODLxo4LUX4oe52gmSCK7Jw4SBghqxA==",
+ "dev": true
+ },
+ "node_modules/vfile-message": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-1.1.1.tgz",
+ "integrity": "sha512-1WmsopSGhWt5laNir+633LszXvZ+Z/lxveBf6yhGsqnQIhlhzooZae7zV6YVM1Sdkw68dtAW3ow0pOdPANugvA==",
+ "dev": true,
+ "dependencies": {
+ "unist-util-stringify-position": "^1.1.1"
+ }
+ },
+ "node_modules/websocket-driver": {
+ "version": "0.7.4",
+ "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
+ "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
+ "dev": true,
+ "dependencies": {
+ "http-parser-js": ">=0.5.1",
+ "safe-buffer": ">=5.1.0",
+ "websocket-extensions": ">=0.1.1"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/websocket-extensions": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz",
+ "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/which": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+ "dev": true,
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "which": "bin/which"
+ }
+ },
+ "node_modules/which-module": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
+ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
+ "dev": true
+ },
+ "node_modules/wide-align": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
+ "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
+ "dev": true,
+ "dependencies": {
+ "string-width": "^1.0.2 || 2"
+ }
+ },
+ "node_modules/word-wrap": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
+ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/wordwrap": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+ "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
+ "dev": true
+ },
+ "node_modules/wrap-ansi": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
+ "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
+ "dev": true,
+ "dependencies": {
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+ "dev": true,
+ "dependencies": {
+ "number-is-nan": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/string-width": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+ "dev": true,
+ "dependencies": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+ "dev": true
+ },
+ "node_modules/write": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz",
+ "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==",
+ "dev": true,
+ "dependencies": {
+ "mkdirp": "^0.5.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/x-is-function": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/x-is-function/-/x-is-function-1.0.4.tgz",
+ "integrity": "sha1-XSlNw9Joy90GJYDgxd93o5HR+h4=",
+ "dev": true
+ },
+ "node_modules/x-is-string": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/x-is-string/-/x-is-string-0.1.0.tgz",
+ "integrity": "sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI=",
+ "dev": true
+ },
+ "node_modules/xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4"
+ }
+ },
+ "node_modules/y18n": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
+ "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
+ "dev": true
+ },
+ "node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
+ },
+ "node_modules/yargs": {
+ "version": "13.2.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.2.tgz",
+ "integrity": "sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA==",
+ "dev": true,
+ "dependencies": {
+ "cliui": "^4.0.0",
+ "find-up": "^3.0.0",
+ "get-caller-file": "^2.0.1",
+ "os-locale": "^3.1.0",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^2.0.0",
+ "set-blocking": "^2.0.0",
+ "string-width": "^3.0.0",
+ "which-module": "^2.0.0",
+ "y18n": "^4.0.0",
+ "yargs-parser": "^13.0.0"
+ }
+ },
+ "node_modules/yargs-parser": {
+ "version": "13.0.0",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.0.0.tgz",
+ "integrity": "sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw==",
+ "dev": true,
+ "dependencies": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
+ }
+ },
+ "node_modules/yargs-parser/node_modules/camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/yargs-unparser": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.5.0.tgz",
+ "integrity": "sha512-HK25qidFTCVuj/D1VfNiEndpLIeJN78aqgR23nL3y4N0U/91cOAzqfHlF8n2BvoNDcZmJKin3ddNSvOxSr8flw==",
+ "dev": true,
+ "dependencies": {
+ "flat": "^4.1.0",
+ "lodash": "^4.17.11",
+ "yargs": "^12.0.5"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/yargs-unparser/node_modules/camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/yargs-unparser/node_modules/find-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/yargs-unparser/node_modules/get-caller-file": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
+ "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
+ "dev": true
+ },
+ "node_modules/yargs-unparser/node_modules/require-main-filename": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
+ "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=",
+ "dev": true
+ },
+ "node_modules/yargs-unparser/node_modules/yargs": {
+ "version": "12.0.5",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz",
+ "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==",
+ "dev": true,
+ "dependencies": {
+ "cliui": "^4.0.0",
+ "decamelize": "^1.2.0",
+ "find-up": "^3.0.0",
+ "get-caller-file": "^1.0.1",
+ "os-locale": "^3.0.0",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^1.0.1",
+ "set-blocking": "^2.0.0",
+ "string-width": "^2.0.0",
+ "which-module": "^2.0.0",
+ "y18n": "^3.2.1 || ^4.0.0",
+ "yargs-parser": "^11.1.1"
+ }
+ },
+ "node_modules/yargs-unparser/node_modules/yargs-parser": {
+ "version": "11.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz",
+ "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==",
+ "dev": true,
+ "dependencies": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
+ }
+ },
+ "node_modules/yargs/node_modules/ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/yargs/node_modules/find-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/yargs/node_modules/string-width": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+ "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+ "dev": true,
+ "dependencies": {
+ "emoji-regex": "^7.0.1",
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/yargs/node_modules/strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ }
+ },
"dependencies": {
"@babel/code-frame": {
"version": "7.10.4",
@@ -7230,9 +19711,9 @@
"optional": true
},
"prettier": {
- "version": "github:automattic/calypso-prettier#c56b42511ec98ba6d8f72b6c391e0a626e90f531",
- "from": "github:automattic/calypso-prettier#c56b4251",
+ "version": "git+ssh://git@github.com/automattic/calypso-prettier.git#c56b42511ec98ba6d8f72b6c391e0a626e90f531",
"dev": true,
+ "from": "prettier@github:automattic/calypso-prettier#c56b4251",
"requires": {
"babel-code-frame": "7.0.0-beta.3",
"babylon": "7.0.0-beta.34",
@@ -8798,6 +21279,15 @@
"readable-stream": "^2.0.1"
}
},
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
"string-template": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz",
@@ -8919,15 +21409,6 @@
}
}
},
- "string_decoder": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "dev": true,
- "requires": {
- "safe-buffer": "~5.1.0"
- }
- },
"stringify-entities": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-1.3.2.tgz",
diff --git a/package.json b/package.json
index a0d197e58..d62df66cb 100644
--- a/package.json
+++ b/package.json
@@ -54,9 +54,9 @@
"mocha": "6.2.0",
"node-sass": ">=4.13.1",
"prettier": "github:automattic/calypso-prettier#c56b4251",
+ "spectre.css": "*",
"stylelint": "10.1.0",
- "stylelint-config-wordpress": "14.0.0",
- "spectre.css": "*"
+ "stylelint-config-wordpress": "14.0.0"
},
"engines": {
"node": ">=10.15.0",
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..4666ce6af
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/assets/css/preferred-services.css
@@ -0,0 +1,153 @@
+#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 .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..65fad3d06
--- /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 .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..0a21d57b3
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/assets/css/preferred-services.scss
@@ -0,0 +1,224 @@
+#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 {
+ .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 000000000..18dab3cf6
Binary files /dev/null and b/packages/woocommerce-germanized-dhl/assets/img/dhl-official.png differ
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 000000000..903d8388b
Binary files /dev/null and b/packages/woocommerce-germanized-dhl/assets/img/packstation.png differ
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 000000000..15fafae42
Binary files /dev/null and b/packages/woocommerce-germanized-dhl/assets/img/parcelshop.png differ
diff --git a/packages/woocommerce-germanized-dhl/assets/img/post_office.png b/packages/woocommerce-germanized-dhl/assets/img/post_office.png
new file mode 100755
index 000000000..097023dcd
Binary files /dev/null and b/packages/woocommerce-germanized-dhl/assets/img/post_office.png differ
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 000000000..a4438cd37
Binary files /dev/null and b/packages/woocommerce-germanized-dhl/assets/img/wp-int-eu-preview.png differ
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 000000000..6ac0f7e34
Binary files /dev/null and b/packages/woocommerce-germanized-dhl/assets/img/wp-int-preview.png differ
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..7def1fe23
--- /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 ).val();
+ }).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..0ce51d112
--- /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(t,n){n.dhl_post_label={params:{},init:function(){var e=n.dhl_post_label;e.params=wc_gzd_admin_deutsche_post_label_params,t(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 t("#wc-gzd-shipment-label-wrapper-additional-services :input:checked").map(function(){return t(this).val()}).get()},onRefreshPreview:function(){var e=n.dhl_post_label,a=germanized.admin.shipment_label_backbone.backbone,i={},d=t(".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,d,e.onPreviewSuccess)},onPreviewSuccess:function(e){var a=n.dhl_post_label,i=t(".wc-gzd-dhl-im-product-data .col-preview"),d=t(".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}}),d.find(".stamp-preview").length<=0&&d.append(' '),a.replaceProductData(e.preview_data),d.find(".stamp-preview").attr("src",e.preview_url).load(function(){i.unblock(),t(this).show()})):d.html("")},refreshProductData:function(){n.dhl_post_label.onRefreshPreview()},getProductId:function(){return t("#wc-gzd-shipment-label-admin-fields-deutsche_post #product_id").val()},replaceProductData:function(a){n.dhl_post_label;var e=t(".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=t(this).data("replace");a.hasOwnProperty(e)?(t(this).html(a[e]),t(this).show()):t(this).hide()})}},t(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..9b268bbb2
--- /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){function o(e,n){var r=e[0],t=e[1],a=e[2],o=e[3];r=i(r,t,a,o,n[0],7,-680876936),o=i(o,r,t,a,n[1],12,-389564586),a=i(a,o,r,t,n[2],17,606105819),t=i(t,a,o,r,n[3],22,-1044525330),r=i(r,t,a,o,n[4],7,-176418897),o=i(o,r,t,a,n[5],12,1200080426),a=i(a,o,r,t,n[6],17,-1473231341),t=i(t,a,o,r,n[7],22,-45705983),r=i(r,t,a,o,n[8],7,1770035416),o=i(o,r,t,a,n[9],12,-1958414417),a=i(a,o,r,t,n[10],17,-42063),t=i(t,a,o,r,n[11],22,-1990404162),r=i(r,t,a,o,n[12],7,1804603682),o=i(o,r,t,a,n[13],12,-40341101),a=i(a,o,r,t,n[14],17,-1502002290),t=i(t,a,o,r,n[15],22,1236535329),r=u(r,t,a,o,n[1],5,-165796510),o=u(o,r,t,a,n[6],9,-1069501632),a=u(a,o,r,t,n[11],14,643717713),t=u(t,a,o,r,n[0],20,-373897302),r=u(r,t,a,o,n[5],5,-701558691),o=u(o,r,t,a,n[10],9,38016083),a=u(a,o,r,t,n[15],14,-660478335),t=u(t,a,o,r,n[4],20,-405537848),r=u(r,t,a,o,n[9],5,568446438),o=u(o,r,t,a,n[14],9,-1019803690),a=u(a,o,r,t,n[3],14,-187363961),t=u(t,a,o,r,n[8],20,1163531501),r=u(r,t,a,o,n[13],5,-1444681467),o=u(o,r,t,a,n[2],9,-51403784),a=u(a,o,r,t,n[7],14,1735328473),t=u(t,a,o,r,n[12],20,-1926607734),r=c(r,t,a,o,n[5],4,-378558),o=c(o,r,t,a,n[8],11,-2022574463),a=c(a,o,r,t,n[11],16,1839030562),t=c(t,a,o,r,n[14],23,-35309556),r=c(r,t,a,o,n[1],4,-1530992060),o=c(o,r,t,a,n[4],11,1272893353),a=c(a,o,r,t,n[7],16,-155497632),t=c(t,a,o,r,n[10],23,-1094730640),r=c(r,t,a,o,n[13],4,681279174),o=c(o,r,t,a,n[0],11,-358537222),a=c(a,o,r,t,n[3],16,-722521979),t=c(t,a,o,r,n[6],23,76029189),r=c(r,t,a,o,n[9],4,-640364487),o=c(o,r,t,a,n[12],11,-421815835),a=c(a,o,r,t,n[15],16,530742520),t=c(t,a,o,r,n[2],23,-995338651),r=m(r,t,a,o,n[0],6,-198630844),o=m(o,r,t,a,n[7],10,1126891415),a=m(a,o,r,t,n[14],15,-1416354905),t=m(t,a,o,r,n[5],21,-57434055),r=m(r,t,a,o,n[12],6,1700485571),o=m(o,r,t,a,n[3],10,-1894986606),a=m(a,o,r,t,n[10],15,-1051523),t=m(t,a,o,r,n[1],21,-2054922799),r=m(r,t,a,o,n[8],6,1873313359),o=m(o,r,t,a,n[15],10,-30611744),a=m(a,o,r,t,n[6],15,-1560198380),t=m(t,a,o,r,n[13],21,1309151649),r=m(r,t,a,o,n[4],6,-145523070),o=m(o,r,t,a,n[11],10,-1120210379),a=m(a,o,r,t,n[2],15,718787259),t=m(t,a,o,r,n[9],21,-343485551),e[0]=f(r,e[0]),e[1]=f(t,e[1]),e[2]=f(a,e[2]),e[3]=f(o,e[3])}function d(e,n,r,t,a,o){return n=f(f(n,e),f(t,o)),f(n<>>32-a,r)}function r(e){for(var n="",r=0;r<4;r++)n+=t[e>>8*r+4&15]+t[e>>8*r&15];return n}var i=function(e,n,r,t,a,o,i){return d(n&r|~n&t,e,n,a,o,i)},u=function(e,n,r,t,a,o,i){return d(n&t|r&~t,e,n,a,o,i)},c=function(e,n,r,t,a,o,i){return d(n^r^t,e,n,a,o,i)},m=function(e,n,r,t,a,o,i){return d(r^(n|~t),e,n,a,o,i)},l=function(e){var n,r=[];for(n=0;n<64;n+=4)r[n>>2]=e.charCodeAt(n)+(e.charCodeAt(n+1)<<8)+(e.charCodeAt(n+2)<<16)+(e.charCodeAt(n+3)<<24);return r},t="0123456789abcdef".split(""),n=e.md5=function(e){return function(e){for(var n=0;n>2]|=e.charCodeAt(n)<<(n%4<<3);if(a[n>>2]|=128<<(n%4<<3),55>16)+(n>>16)+(r>>16)<<16|65535&r}}(window),function(u,n,c){n.dhl_internetmarke={params:{},init:function(){var e=n.dhl_internetmarke;u(document).on("click","#woocommerce_gzd_dhl_im_portokasse_charge",e.onCharge)},onCharge:function(){var e=u(this),n=e.data(),r=u("#woocommerce_gzd_dhl_im_portokasse_charge_amount").val();$form=u('').appendTo("body"),u.each(n,function(e,n){$form.append(' ')});var t=parseInt((100*parseFloat(r.replace(",",".")).toFixed(2)).toFixed()),a=parseInt(n.wallet);(t<1e3||Number.isNaN(t))&&(t=1e3);var o=new Date,i=("0"+o.getDate()).slice(-2)+("0"+(o.getMonth()+1)).slice(-2)+o.getFullYear().toString()+"-"+("0"+o.getHours()).slice(-2)+("0"+o.getMinutes()).slice(-2)+("0"+o.getSeconds()).slice(-2),d=[n.partner_id,i,n.success_url,n.cancel_url,n.user_token,a+t,n.schluessel_dpwn_partner].join("::");return $form.append(' '),$form.append(' '),$form.append(' '),$form.submit(),!1}},u(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( '' );
+ }
+ };
+
+ $( 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..616358279
--- /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,p=e.getModal(),r=a.getShippingMethod(),n=a.getShippingMethodData(r);n&&(p.find(".finder-pickup-type").addClass("hidden"),o.each(n.supports,function(e,a){var r=p.find('.finder-pickup-type[data-pickup_type="'+a+'"]');r.find("input[type=checkbox]").prop("checked",!0),r.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..8995b6902
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/assets/js/parcel-locator.js
@@ -0,0 +1,400 @@
+
+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( 'updated_checkout', self.afterRefreshCheckout );
+
+ self.refreshAvailability();
+ self.refreshAddressType();
+ },
+
+ 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( $( ' ', {
+ value: name,
+ text : title
+ }));
+ });
+
+ if ( $typeField.find( 'option[value="' + selected + '"]' ).length > 0 ) {
+ $typeField.find( 'option[value="' + selected + '"]' ).prop( 'selected', true );
+ }
+
+ $typeField.trigger( 'change' );
+ }
+ }
+
+ if ( $typeField.find( 'option' ).length > 0 ) {
+ $( self.wrapper + ' #shipping_address_type_field' ).show();
+ } else {
+ $( self.wrapper + ' #shipping_address_type_field' ).hide();
+ }
+
+ $( document.body ).trigger( 'woocommerce_gzd_dhl_location_available_pickup_types_changed' );
+ }
+ },
+
+ onChangeShipping: function() {
+ var self = germanized.dhl_parcel_locator,
+ $checkbox = $( this );
+
+ if ( $checkbox.is( ':checked' ) ) {
+ self.refreshAvailability();
+
+ if ( self.isEnabled() ) {
+ self.refreshAddressType();
+ }
+ }
+ },
+
+ onChangeAddress: function() {
+ var self = germanized.dhl_parcel_locator;
+
+ if ( self.isEnabled() ) {
+ self.formatAddress();
+ }
+ },
+
+ formatAddress: function() {
+ var needsValidation = false,
+ self = germanized.dhl_parcel_locator,
+ $addressField = $( self.wrapper + ' #shipping_address_1' ),
+ address = $addressField.val();
+
+ if ( address.length > 0 ) {
+ if ( $.isNumeric( address ) ) {
+ needsValidation = true;
+ } else if ( self.addressIsPackstation() || self.addressIsPostOffice() || self.addressIsParcelShop() ) {
+
+ } else {
+ $addressField.val( '' );
+ }
+ }
+
+ if ( needsValidation ) {
+ self.validateAddress( address );
+ }
+
+ self.refreshCustomerNumberStatus();
+ },
+
+ addressIsPackstation: function() {
+ var self = germanized.dhl_parcel_locator,
+ addressVal = $( self.wrapper + ' #shipping_address_1' ).val().toLowerCase();
+
+ if ( addressVal.indexOf( self.params.i18n.packstation.toLowerCase() ) >= 0 ) {
+ return true;
+ }
+
+ return false;
+ },
+
+ addressIsPostOffice: function() {
+ var self = germanized.dhl_parcel_locator,
+ addressVal = $( self.wrapper + ' #shipping_address_1' ).val().toLowerCase();
+
+ if ( addressVal.indexOf( self.params.i18n.postoffice.toLowerCase() ) >= 0 ) {
+ return true;
+ }
+
+ return false;
+ },
+
+ addressIsParcelShop: function() {
+ var self = germanized.dhl_parcel_locator,
+ addressVal = $( self.wrapper + ' #shipping_address_1' ).val().toLowerCase();
+
+ if ( addressVal.indexOf( self.params.i18n.parcelshop.toLowerCase() ) >= 0 ) {
+ return true;
+ }
+
+ return false;
+ },
+
+ shippingMethodSupportsPickupType: function( method, pickupType ) {
+ var self = germanized.dhl_parcel_locator,
+ data = self.getShippingMethodData( method ),
+ supports = false;
+
+ if ( data ) {
+ if ( $.inArray( pickupType, data.supports ) !== -1 ) {
+ supports = true;
+ }
+ }
+
+ return supports;
+ },
+
+ customerNumberIsMandatory: function() {
+ var self = germanized.dhl_parcel_locator;
+
+ if ( ! self.isEnabled() ) {
+ return false;
+ }
+
+ if ( self.addressIsPackstation() ) {
+ return true;
+ } else if ( self.addressIsParcelShop() ) {
+ return false;
+ } else if ( self.addressIsPostOffice() ) {
+ return false;
+ }
+
+ return false;
+ },
+
+ refreshCustomerNumberStatus: function() {
+ var self = germanized.dhl_parcel_locator,
+ $field = $( self.wrapper + ' #shipping_dhl_postnumber_field' );
+
+ if ( self.customerNumberIsMandatory() ) {
+ if ( ! $field.find( 'label span' ).length || ( ! $field.find( 'label span' ).hasClass( 'required' ) ) ) {
+ $field.find( 'label' ).append( ' * ' );
+ }
+
+ $field.find( 'label span.optional' ).hide();
+ $field.addClass( 'validate-required' );
+ } else {
+ $field.find( 'label span.required' ).remove();
+ $field.find( 'label span.optional' ).show();
+
+ $field.removeClass( 'validate-required woocommerce-invalid woocommerce-invalid-required-field' );
+ }
+ },
+
+ validateAddress: function( addressData ) {
+ var self = germanized.dhl_parcel_locator,
+ params = {
+ 'action' : 'woocommerce_gzd_dhl_parcel_locator_validate_address',
+ 'address' : addressData,
+ 'security': self.params.parcel_locator_nonce
+ };
+
+ $.ajax({
+ type: "POST",
+ url: self.params.ajax_url,
+ data: params,
+ success: function( data ) {
+ if ( data.valid ) {
+ $( self.wrapper + ' #shipping_address_1' ).val( data.address );
+ self.refreshCustomerNumberStatus();
+ } else {
+ $( self.wrapper + ' #shipping_address_1' ).val( '' );
+ }
+ },
+ error: function( data ) {},
+ dataType: 'json'
+ });
+ },
+
+ getShippingMethodData: function( method ) {
+ var self = germanized.dhl_parcel_locator;
+
+ if ( self.params.methods.hasOwnProperty( method ) ) {
+ return self.params.methods[ method ];
+ }
+
+ return false;
+ },
+
+ refreshAddressType: function() {
+ var self = germanized.dhl_parcel_locator,
+ $addressField = $( self.wrapper + ' #shipping_address_1_field' ),
+ $addressInput = $( self.wrapper + ' #shipping_address_1' ),
+ shippingMethod = self.getShippingMethod(),
+ methodData = self.getShippingMethodData( shippingMethod ),
+ address = $addressInput.val(),
+ $spans;
+
+ if ( self.isEnabled() ) {
+
+ if ( methodData ) {
+ $addressInput.data( 'label-dhl', methodData.street_label );
+ $addressInput.data( 'placeholder-dhl', methodData.street_placeholder );
+ $addressInput.data( 'desc-dhl', methodData.finder_button );
+ }
+
+ $( self.wrapper + ' #shipping_dhl_postnumber_field' ).show();
+
+ if ( $addressInput.data( 'label-dhl' ) ) {
+ $spans = $addressField.find( 'label span, label abbr' );
+
+ $addressField.find( 'label' ).html( $addressInput.data( 'label-dhl' ) + ' ' );
+ $addressField.find( 'label' ).append( $spans );
+ }
+
+ if ( $addressInput.data( 'placeholder-dhl' ) ) {
+ $addressInput.attr( 'placeholder', $addressInput.data( 'placeholder-dhl' ) );
+ }
+
+ if ( $addressInput.data( 'desc-dhl' ) ) {
+ $addressField.find( '.dhl-desc' ).remove();
+ $addressField.find( '.woocommerce-input-wrapper' ).after( '' + $addressInput.data( 'desc-dhl' ) + '
' );
+ }
+
+ if ( address.length > 0 ) {
+ self.formatAddress();
+ }
+ } else {
+ $( self.wrapper + ' #shipping_dhl_postnumber_field' ).hide();
+
+ if ( $addressInput.data( 'label-regular' ) ) {
+ $spans = $addressField.find( 'label span, label abbr' );
+
+ $addressField.find( 'label' ).html( $addressInput.data( 'label-regular' ) + ' ' );
+ $addressField.find( 'label' ).append( $spans );
+ }
+
+ if ( $addressInput.data( 'placeholder-regular' ) ) {
+ $addressInput.attr( 'placeholder', $addressInput.data( 'placeholder-regular' ) );
+ }
+
+ $addressField.find( '.dhl-desc' ).remove();
+ }
+ },
+
+ isEnabled: function() {
+ var self = germanized.dhl_parcel_locator;
+
+ return self.isAvailable() && $( self.wrapper + ' #shipping_address_type' ).val() === 'dhl';
+ },
+
+ getShippingMethod: function( pwithInstanceId ) {
+ var current = '';
+ var withInstanceId = pwithInstanceId ? pwithInstanceId : true;
+
+ if ( $( 'select.shipping_method' ).length > 0 ) {
+ current = $( 'select.shipping_method' ).val();
+ } else if ( $( 'input[name^="shipping_method"]:checked' ).length > 0 ) {
+ current = $( 'input[name^="shipping_method"]:checked' ).val();
+ } else if ( $( 'input[name^="shipping_method"][type="hidden"]' ).length > 0 ) {
+ current = $( 'input[name^="shipping_method"][type="hidden"]' ).val();
+ }
+
+ if ( ! withInstanceId ) {
+ if ( 'undefined' !== typeof current && current.length > 0 ) {
+ var currentParts = current.split(':');
+
+ if ( currentParts.length > 0 ) {
+ current = currentParts[0];
+ }
+ }
+ } else {
+ // In case an instance id is needed but missing - assume 0 as instance id
+ if ( 'undefined' !== typeof current && current.length > 0 ) {
+ var currentParts = current.split(':');
+
+ if ( currentParts.length <= 1 ) {
+ current = current + ':0';
+ }
+ }
+ }
+
+ return current;
+ },
+
+ pickupTypeIsAvailable: function( pickupType ) {
+ var self = germanized.dhl_parcel_locator,
+ shippingMethod = self.getShippingMethod(),
+ isAvailable = true;
+
+ if ( ! self.shippingMethodSupportsPickupType( shippingMethod, pickupType ) ) {
+ isAvailable = false;
+ }
+
+ return isAvailable;
+ },
+
+ isAvailable: function() {
+ var self = germanized.dhl_parcel_locator,
+ shippingCountry = $( self.wrapper + ' #shipping_country' ).val(),
+ shippingMethod = self.getShippingMethod(),
+ methodData = self.getShippingMethodData( shippingMethod ),
+ isAvailable = true;
+
+ if ( $.inArray( shippingCountry, self.params.supported_countries ) === -1 ) {
+ isAvailable = false;
+ }
+
+ if ( self.isCheckout() ) {
+ if ( ! methodData || methodData.supports.length === 0 ) {
+ isAvailable = false;
+ }
+ }
+
+ return isAvailable;
+ }
+ };
+
+ $( document ).ready( function() {
+ germanized.dhl_parcel_locator.init();
+ });
+
+})( jQuery, window.germanized );
diff --git a/packages/woocommerce-germanized-dhl/assets/js/parcel-locator.min.js b/packages/woocommerce-germanized-dhl/assets/js/parcel-locator.min.js
new file mode 100644
index 000000000..8ae25b855
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/assets/js/parcel-locator.min.js
@@ -0,0 +1 @@
+window.germanized=window.germanized||{},window.germanized.dhl_parcel_locator=window.germanized.dhl_parcel_locator||{},function(s,i){i.dhl_parcel_locator={params:{},parcelShops:[],wrapper:"",init:function(){var e=i.dhl_parcel_locator;e.params=wc_gzd_dhl_parcel_locator_params,e.wrapper=e.params.wrapper,s(document).on("change.dhl",e.wrapper+" #shipping_address_type",e.refreshAddressType).on("change.dhl",e.wrapper+" #shipping_address_1",e.onChangeAddress).on("change.dhl",e.wrapper+" #ship-to-different-address-checkbox",e.onChangeShipping).on("change.dhl",e.wrapper+" #shipping_country",e.refreshAvailability),s(document.body).on("updated_checkout",e.afterRefreshCheckout),e.refreshAvailability(),e.refreshAddressType()},isCheckout:function(){return i.dhl_parcel_locator.params.is_checkout},afterRefreshCheckout:function(){var a=i.dhl_parcel_locator,e={security:a.params.parcel_locator_data_nonce,action:"woocommerce_gzd_dhl_parcel_locator_refresh_shipping_data"};s.ajax({type:"POST",url:a.params.ajax_url,data:e,success:function(e){a.params.methods=e.methods,a.refreshAvailability()},error:function(e){a.refreshAvailability()},dataType:"json"})},refreshAvailability:function(){var e=i.dhl_parcel_locator,a=e.getShippingMethod(),r=e.getShippingMethodData(a);if(e.isAvailable()){var d=s(e.wrapper+" #shipping_address_type"),p=d.val();e.isCheckout()&&(d.html(""),r&&(s.each(r.address_type_options,function(e,a){d.append(s(" ",{value:e,text:a}))}),0*'),a.find("label span.optional").hide(),a.addClass("validate-required")):(a.find("label span.required").remove(),a.find("label span.optional").show(),a.removeClass("validate-required woocommerce-invalid woocommerce-invalid-required-field"))},validateAddress:function(e){var a=i.dhl_parcel_locator,r={action:"woocommerce_gzd_dhl_parcel_locator_validate_address",address:e,security:a.params.parcel_locator_nonce};s.ajax({type:"POST",url:a.params.ajax_url,data:r,success:function(e){e.valid?(s(a.wrapper+" #shipping_address_1").val(e.address),a.refreshCustomerNumberStatus()):s(a.wrapper+" #shipping_address_1").val("")},error:function(e){},dataType:"json"})},getShippingMethodData:function(e){var a=i.dhl_parcel_locator;return!!a.params.methods.hasOwnProperty(e)&&a.params.methods[e]},refreshAddressType:function(){var e,a=i.dhl_parcel_locator,r=s(a.wrapper+" #shipping_address_1_field"),d=s(a.wrapper+" #shipping_address_1"),p=a.getShippingMethod(),t=a.getShippingMethodData(p),l=d.val();a.isEnabled()?(t&&(d.data("label-dhl",t.street_label),d.data("placeholder-dhl",t.street_placeholder),d.data("desc-dhl",t.finder_button)),s(a.wrapper+" #shipping_dhl_postnumber_field").show(),d.data("label-dhl")&&(e=r.find("label span, label abbr"),r.find("label").html(d.data("label-dhl")+" "),r.find("label").append(e)),d.data("placeholder-dhl")&&d.attr("placeholder",d.data("placeholder-dhl")),d.data("desc-dhl")&&(r.find(".dhl-desc").remove(),r.find(".woocommerce-input-wrapper").after(''+d.data("desc-dhl")+"
")),0 0 ) {
+ if ( 'place' === $box.val() ) {
+ $( '.dhl-preferred-service-content .dhl-preferred-service-location-place' ).show();
+ } else if ( 'neighbor' === $box.val() ) {
+ $( '.dhl-preferred-service-content .dhl-preferred-service-location-neighbor' ).show();
+ }
+ }
+ },
+
+ initTipTip: function() {
+
+ // Remove any lingering tooltips
+ $( '#tiptip_holder' ).removeAttr( 'style' );
+ $( '#tiptip_arrow' ).removeAttr( 'style' );
+
+ $( '.dhl-preferred-service-content .woocommerce-help-tip' ).tipTip({
+ 'attribute': 'data-tip',
+ 'fadeIn': 50,
+ 'fadeOut': 50,
+ 'delay': 200
+ });
+ }
+ };
+
+ $( document ).ready( function() {
+ germanized.dhl_preferred_services.init();
+ });
+
+})( jQuery, window.germanized );
diff --git a/packages/woocommerce-germanized-dhl/assets/js/preferred-services.min.js b/packages/woocommerce-germanized-dhl/assets/js/preferred-services.min.js
new file mode 100644
index 000000000..27bec0320
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/assets/js/preferred-services.min.js
@@ -0,0 +1 @@
+window.germanized=window.germanized||{},window.germanized.dhl_preferred_services=window.germanized.dhl_preferred_services||{},function(r,t){t.dhl_preferred_services={params:{},init:function(){var e=t.dhl_preferred_services;e.params=wc_gzd_dhl_preferred_services_params,r(document.body).on("updated_checkout",e.afterRefreshCheckout),r(document).on("change",".dhl-preferred-service-content .dhl-preferred-location-types input",e.onChangeLocationType).on("change",".woocommerce-checkout #billing_postcode",e.triggerCheckoutRefresh).on("change",".woocommerce-checkout #shipping_postcode",e.triggerCheckoutRefresh).on("change",".dhl-preferred-service-content .dhl-preferred-service-times input",e.triggerCheckoutRefresh),e.params.payment_gateways_excluded&&r(document).on("change",".payment_methods .input-radio",e.triggerCheckoutRefresh),e.afterRefreshCheckout()},triggerCheckoutRefresh:function(){r(document.body).trigger("update_checkout")},afterRefreshCheckout:function(){var e=t.dhl_preferred_services;e.initTipTip(),e.onChangeLocationType()},onChangeLocationType:function(){t.dhl_preferred_services;var e=r(".dhl-preferred-service-content .dhl-preferred-location-types input:checked");r(".dhl-preferred-service-content .dhl-preferred-service-location-data").hide(),0 array(
+ '2021-01-06',
+ '2021-06-03',
+ '2021-04-04',
+ '2021-03-08',
+ '2021-11-01',
+ '2021-05-13',
+ '2021-05-01',
+ '2021-12-26',
+ '2021-10-03',
+ '2021-09-20',
+ '2021-08-08',
+ '2021-11-17',
+ '2021-01-01',
+ '2021-10-31',
+ '2021-05-24',
+ '2021-08-15',
+ '2021-04-02',
+ '2021-12-25',
+ '2021-04-01',
+ '2021-05-23',
+ '2021-04-05',
+ '2022-01-06',
+ '2022-06-16',
+ '2022-04-17',
+ '2022-03-08',
+ '2022-11-01',
+ '2022-05-26',
+ '2022-05-01',
+ '2022-12-26',
+ '2022-10-03',
+ '2022-09-20',
+ '2022-08-08',
+ '2022-11-16',
+ '2022-01-01',
+ '2022-10-31',
+ '2022-06-06',
+ '2022-08-15',
+ '2022-04-15',
+ '2022-12-25',
+ '2022-04-14',
+ '2022-06-05',
+ '2022-04-18',
+ ),
+);
diff --git a/packages/woocommerce-germanized-dhl/i18n/iso.php b/packages/woocommerce-germanized-dhl/i18n/iso.php
new file mode 100644
index 000000000..b6c88fe47
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/i18n/iso.php
@@ -0,0 +1,260 @@
+ 'AFG',
+ 'AX' => 'ALA',
+ 'AL' => 'ALB',
+ 'DZ' => 'DZA',
+ 'AS' => 'ASM',
+ 'AD' => 'AND',
+ 'AO' => 'AGO',
+ 'AI' => 'AIA',
+ 'AQ' => 'ATA',
+ 'AG' => 'ATG',
+ 'AR' => 'ARG',
+ 'AM' => 'ARM',
+ 'AW' => 'ABW',
+ 'AU' => 'AUS',
+ 'AT' => 'AUT',
+ 'AZ' => 'AZE',
+ 'BS' => 'BHS',
+ 'BH' => 'BHR',
+ 'BD' => 'BGD',
+ 'BB' => 'BRB',
+ 'BY' => 'BLR',
+ 'BE' => 'BEL',
+ 'BZ' => 'BLZ',
+ 'BJ' => 'BEN',
+ 'BM' => 'BMU',
+ 'BT' => 'BTN',
+ 'BO' => 'BOL',
+ 'BA' => 'BIH',
+ 'BW' => 'BWA',
+ 'BV' => 'BVT',
+ 'BR' => 'BRA',
+ 'VG' => 'VGB',
+ 'IO' => 'IOT',
+ 'BN' => 'BRN',
+ 'BG' => 'BGR',
+ 'BF' => 'BFA',
+ 'BI' => 'BDI',
+ 'KH' => 'KHM',
+ 'CM' => 'CMR',
+ 'CA' => 'CAN',
+ 'CV' => 'CPV',
+ 'KY' => 'CYM',
+ 'CF' => 'CAF',
+ 'TD' => 'TCD',
+ 'CL' => 'CHL',
+ 'CN' => 'CHN',
+ 'HK' => 'HKG',
+ 'MO' => 'MAC',
+ 'CX' => 'CXR',
+ 'CC' => 'CCK',
+ 'CO' => 'COL',
+ 'KM' => 'COM',
+ 'CG' => 'COG',
+ 'CD' => 'COD',
+ 'CK' => 'COK',
+ 'CR' => 'CRI',
+ 'CI' => 'CIV',
+ 'HR' => 'HRV',
+ 'CU' => 'CUB',
+ 'CY' => 'CYP',
+ 'CZ' => 'CZE',
+ 'DK' => 'DNK',
+ 'DJ' => 'DJI',
+ 'DM' => 'DMA',
+ 'DO' => 'DOM',
+ 'EC' => 'ECU',
+ 'EG' => 'EGY',
+ 'SV' => 'SLV',
+ 'GQ' => 'GNQ',
+ 'ER' => 'ERI',
+ 'EE' => 'EST',
+ 'ET' => 'ETH',
+ 'FK' => 'FLK',
+ 'FO' => 'FRO',
+ 'FJ' => 'FJI',
+ 'FI' => 'FIN',
+ 'FR' => 'FRA',
+ 'GF' => 'GUF',
+ 'PF' => 'PYF',
+ 'TF' => 'ATF',
+ 'GA' => 'GAB',
+ 'GM' => 'GMB',
+ 'GE' => 'GEO',
+ 'DE' => 'DEU',
+ 'GH' => 'GHA',
+ 'GI' => 'GIB',
+ 'GR' => 'GRC',
+ 'GL' => 'GRL',
+ 'GD' => 'GRD',
+ 'GP' => 'GLP',
+ 'GU' => 'GUM',
+ 'GT' => 'GTM',
+ 'GG' => 'GGY',
+ 'GN' => 'GIN',
+ 'GW' => 'GNB',
+ 'GY' => 'GUY',
+ 'HT' => 'HTI',
+ 'HM' => 'HMD',
+ 'VA' => 'VAT',
+ 'HN' => 'HND',
+ 'HU' => 'HUN',
+ 'IS' => 'ISL',
+ 'IN' => 'IND',
+ 'ID' => 'IDN',
+ 'IR' => 'IRN',
+ 'IQ' => 'IRQ',
+ 'IE' => 'IRL',
+ 'IM' => 'IMN',
+ 'IL' => 'ISR',
+ 'IT' => 'ITA',
+ 'JM' => 'JAM',
+ 'JP' => 'JPN',
+ 'JE' => 'JEY',
+ 'JO' => 'JOR',
+ 'KZ' => 'KAZ',
+ 'KE' => 'KEN',
+ 'KI' => 'KIR',
+ 'KP' => 'PRK',
+ 'KR' => 'KOR',
+ 'KW' => 'KWT',
+ 'KG' => 'KGZ',
+ 'LA' => 'LAO',
+ 'LV' => 'LVA',
+ 'LB' => 'LBN',
+ 'LS' => 'LSO',
+ 'LR' => 'LBR',
+ 'LY' => 'LBY',
+ 'LI' => 'LIE',
+ 'LT' => 'LTU',
+ 'LU' => 'LUX',
+ 'MK' => 'MKD',
+ 'MG' => 'MDG',
+ 'MW' => 'MWI',
+ 'MY' => 'MYS',
+ 'MV' => 'MDV',
+ 'ML' => 'MLI',
+ 'MT' => 'MLT',
+ 'MH' => 'MHL',
+ 'MQ' => 'MTQ',
+ 'MR' => 'MRT',
+ 'MU' => 'MUS',
+ 'YT' => 'MYT',
+ 'MX' => 'MEX',
+ 'FM' => 'FSM',
+ 'MD' => 'MDA',
+ 'MC' => 'MCO',
+ 'MN' => 'MNG',
+ 'ME' => 'MNE',
+ 'MS' => 'MSR',
+ 'MA' => 'MAR',
+ 'MZ' => 'MOZ',
+ 'MM' => 'MMR',
+ 'NA' => 'NAM',
+ 'NR' => 'NRU',
+ 'NP' => 'NPL',
+ 'NL' => 'NLD',
+ 'AN' => 'ANT',
+ 'NC' => 'NCL',
+ 'NZ' => 'NZL',
+ 'NI' => 'NIC',
+ 'NE' => 'NER',
+ 'NG' => 'NGA',
+ 'NU' => 'NIU',
+ 'NF' => 'NFK',
+ 'MP' => 'MNP',
+ 'NO' => 'NOR',
+ 'OM' => 'OMN',
+ 'PK' => 'PAK',
+ 'PW' => 'PLW',
+ 'PS' => 'PSE',
+ 'PA' => 'PAN',
+ 'PG' => 'PNG',
+ 'PY' => 'PRY',
+ 'PE' => 'PER',
+ 'PH' => 'PHL',
+ 'PN' => 'PCN',
+ 'PL' => 'POL',
+ 'PT' => 'PRT',
+ 'PR' => 'PRI',
+ 'QA' => 'QAT',
+ 'RE' => 'REU',
+ 'RO' => 'ROU',
+ 'RU' => 'RUS',
+ 'RW' => 'RWA',
+ 'BL' => 'BLM',
+ 'SH' => 'SHN',
+ 'KN' => 'KNA',
+ 'LC' => 'LCA',
+ 'MF' => 'MAF',
+ 'PM' => 'SPM',
+ 'VC' => 'VCT',
+ 'WS' => 'WSM',
+ 'SM' => 'SMR',
+ 'ST' => 'STP',
+ 'SA' => 'SAU',
+ 'SN' => 'SEN',
+ 'RS' => 'SRB',
+ 'SC' => 'SYC',
+ 'SL' => 'SLE',
+ 'SG' => 'SGP',
+ 'SK' => 'SVK',
+ 'SI' => 'SVN',
+ 'SB' => 'SLB',
+ 'SO' => 'SOM',
+ 'ZA' => 'ZAF',
+ 'GS' => 'SGS',
+ 'SS' => 'SSD',
+ 'ES' => 'ESP',
+ 'LK' => 'LKA',
+ 'SD' => 'SDN',
+ 'SR' => 'SUR',
+ 'SJ' => 'SJM',
+ 'SZ' => 'SWZ',
+ 'SE' => 'SWE',
+ 'CH' => 'CHE',
+ 'SY' => 'SYR',
+ 'TW' => 'TWN',
+ 'TJ' => 'TJK',
+ 'TZ' => 'TZA',
+ 'TH' => 'THA',
+ 'TL' => 'TLS',
+ 'TG' => 'TGO',
+ 'TK' => 'TKL',
+ 'TO' => 'TON',
+ 'TT' => 'TTO',
+ 'TN' => 'TUN',
+ 'TR' => 'TUR',
+ 'TM' => 'TKM',
+ 'TC' => 'TCA',
+ 'TV' => 'TUV',
+ 'UG' => 'UGA',
+ 'UA' => 'UKR',
+ 'AE' => 'ARE',
+ 'GB' => 'GBR',
+ 'US' => 'USA',
+ 'UM' => 'UMI',
+ 'UY' => 'URY',
+ 'UZ' => 'UZB',
+ 'VU' => 'VUT',
+ 'VE' => 'VEN',
+ 'VN' => 'VNM',
+ 'VI' => 'VIR',
+ 'WF' => 'WLF',
+ 'EH' => 'ESH',
+ 'YE' => 'YEM',
+ 'ZM' => 'ZMB',
+ 'ZW' => 'ZWE'
+);
diff --git a/packages/woocommerce-germanized-dhl/includes/wc-gzd-dhl-core-functions.php b/packages/woocommerce-germanized-dhl/includes/wc-gzd-dhl-core-functions.php
new file mode 100644
index 000000000..7433004c0
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/includes/wc-gzd-dhl-core-functions.php
@@ -0,0 +1,914 @@
+get_shipment() ) {
+ return false;
+ }
+
+ $customs_items = array();
+ $item_description = '';
+ $total_weight = wc_gzd_dhl_round_customs_item_weight( wc_add_number_precision( $label->get_net_weight() ) );
+ $item_weights = array();
+ $shipment_items = $shipment->get_items();
+
+ 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_total_weight = array_sum( $item_weights );
+ $item_count = sizeof( $item_weights );
+
+ /**
+ * Discrepancies detected between item weights an total shipment weight.
+ * Try to distribute the mismatch between items.
+ */
+ if ( $item_total_weight != $total_weight ) {
+ $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 = wc_gzd_dhl_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;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ 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( ( $item->get_subtotal() / $item->get_quantity() ) );
+ $dhl_product = false;
+ $product = $item->get_product();
+
+ if ( $product ) {
+ $dhl_product = wc_gzd_dhl_get_product( $product );
+ }
+
+ if ( $product_total < 0.01 ) {
+ // Use the order item subtotal amount as fallback
+ if ( ( $order_item = $item->get_order_item() ) && ( $order = $shipment->get_order() ) ) {
+ $order_item_subtotal = $order->get_line_subtotal( $order_item, true );
+ $product_total = floatval( ( $order_item_subtotal / $item->get_quantity() ) );
+ }
+ }
+
+ $category = $dhl_product ? $dhl_product->get_main_category() : $item->get_name();
+
+ if ( empty( $category ) ) {
+ $category = $item->get_name();
+ }
+
+ $json_item = apply_filters( 'woocommerce_gzd_dhl_customs_item', array(
+ 'description' => wc_clean( substr( $item->get_name(), 0, 255 ) ),
+ 'countryCodeOrigin' => ( $dhl_product && $dhl_product->get_manufacture_country() ) ? $dhl_product->get_manufacture_country() : Package::get_base_country(),
+ 'customsTariffNumber' => $dhl_product ? $dhl_product->get_hs_code() : '',
+ 'amount' => intval( $item->get_quantity() ),
+ /**
+ * netWeightInKG is defined as the weight per item (e.g. 2 items in case the quantity equals 2).
+ */
+ 'netWeightInKG' => wc_gzd_dhl_round_customs_item_weight( wc_remove_number_precision( $item_weights[ $key ] / $item->get_quantity() ), 2 ),
+ 'customsValue' => $product_total < 0.01 ? wc_format_decimal( apply_filters( 'woocommerce_gzd_dhl_customs_item_min_price', 0.01, $item, $shipment ), 2 ) : wc_format_decimal( $product_total, 2 )
+ ), $item, $shipment, $label );
+
+ array_push($customsDetails, $json_item );
+ }
+
+ $item_description = substr( $item_description, 0, 255 );
+
+ return apply_filters( 'woocommerce_gzd_dhl_customs_data', array(
+ 'invoiceNumber' => $shipment->get_id(),
+ 'additionalFee' => wc_format_decimal( $shipment->get_additional_total(), 2 ),
+ 'exportTypeDescription' => $item_description,
+ 'placeOfCommital' => $shipment->get_country(),
+ 'ExportDocPosition' => $customsDetails
+ ), $shipment, $label );
+}
+
+function wc_gzd_dhl_format_preferred_api_time( $time ) {
+ return str_replace( array( ':', '-' ), '', $time );
+}
+
+/**
+ * @param false|Shipment $shipment
+ *
+ * @return array
+ */
+function wc_gzd_dhl_get_label_payment_ref_placeholder( $shipment = false ) {
+ return apply_filters( 'woocommerce_gzd_dhl_label_payment_ref_placeholder', array(
+ '{shipment_id}' => $shipment ? $shipment->get_shipment_number() : '',
+ '{order_id}' => $shipment ? $shipment->get_order_number() : '',
+ '{email}' => $shipment ? $shipment->get_email() : ''
+ ) );
+}
+
+function wc_gzd_dhl_get_preferred_days_select_options( $days, $current = '' ) {
+ $preferred_days = array( 0 => _x( 'None', 'dhl day context', 'woocommerce-germanized' ) );
+
+ if ( ! empty( $days ) ) {
+ $days = array_keys( $days );
+
+ foreach( $days as $day ) {
+
+ if ( empty( $day ) ) {
+ continue;
+ }
+
+ $date = new \WC_DateTime( $day );
+ $date->setTimezone( new DateTimeZone( 'Europe/Berlin' ) );
+
+ $formatted_day = $date->date_i18n( wc_date_format() );
+ $preferred_days = array_merge( $preferred_days, array( $day => $formatted_day ) );
+ }
+ }
+
+ if ( ! empty( $current ) ) {
+ $date = new \WC_DateTime( $current );
+ $date->setTimezone( new DateTimeZone( 'Europe/Berlin' ) );
+
+ $preferred_days[ $current ] = $date->date_i18n( wc_date_format() );
+ }
+
+ return $preferred_days;
+}
+
+function wc_gzd_dhl_get_duties() {
+ $duties = array(
+ 'DDU' => _x( 'Delivery Duty Unpaid', 'dhl', 'woocommerce-germanized' ),
+ 'DDP' => _x( 'Delivery Duty Paid', 'dhl', 'woocommerce-germanized' ),
+ 'DXV' => _x( 'Delivery Duty Paid (excl. VAT )', 'dhl', 'woocommerce-germanized' ),
+ 'DDX' => _x( 'Delivery Duty Paid (excl. Duties, taxes and VAT)', 'dhl', 'woocommerce-germanized' )
+ );
+
+ return $duties;
+}
+
+function wc_gzd_dhl_is_valid_visual_min_age( $min_age ) {
+ $ages = wc_gzd_dhl_get_visual_min_ages();
+
+ if ( empty( $min_age ) || ( ! array_key_exists( $min_age, $ages ) && ! in_array( $min_age, $ages ) ) ) {
+ return false;
+ }
+
+ return true;
+}
+
+function wc_gzd_dhl_is_valid_ident_min_age( $min_age ) {
+ $ages = wc_gzd_dhl_get_ident_min_ages();
+
+ if ( empty( $min_age ) || ( ! array_key_exists( $min_age, $ages ) && ! in_array( $min_age, $ages ) ) ) {
+ return false;
+ }
+
+ return true;
+}
+
+function wc_gzd_dhl_get_visual_min_ages() {
+ $visual_age = array(
+ '0' => _x( 'None', 'age context', 'woocommerce-germanized' ),
+ 'A16' => _x( 'Minimum age of 16', 'dhl', 'woocommerce-germanized' ),
+ 'A18' => _x( 'Minimum age of 18', 'dhl', 'woocommerce-germanized' )
+ );
+
+ return $visual_age;
+}
+
+function wc_gzd_dhl_get_ident_min_ages() {
+ return wc_gzd_dhl_get_visual_min_ages();
+}
+
+function wc_gzd_dhl_get_label_reference( $reference_text, $placeholders = array() ) {
+ return str_replace( array_keys( $placeholders ), array_values( $placeholders ), $reference_text );
+}
+
+function wc_gzd_dhl_get_label_customer_reference( $label, $shipment ) {
+ /**
+ * Filter to adjust the customer reference field placed on the DHL label. Maximum characeter length: 35.
+ *
+ * @param string $text The customer reference text.
+ * @param Label\Label $label The label instance.
+ * @param SimpleShipment $shipment The shipment instance.
+ *
+ * @since 3.0.0
+ * @package Vendidero/Germanized/DHL
+ */
+ $ref = apply_filters( 'woocommerce_gzd_dhl_label_customer_reference', wc_gzd_dhl_get_label_reference( _x( 'Shipment #{shipment_id} to order {order_id}', 'dhl', 'woocommerce-germanized' ), array( '{shipment_id}' => $shipment->get_id(), '{order_id}' => $shipment->get_order_number() ) ), $label, $shipment );
+
+ return sanitize_text_field( substr( $ref, 0, 35 ) );
+}
+
+function wc_gzd_dhl_get_return_label_customer_reference( $label, $shipment ) {
+ /**
+ * Filter to adjust the customer reference field placed on the DHL return label. Maximum characeter length: 30.
+ *
+ * @param string $text The customer reference text.
+ * @param Label\Label $label The label instance.
+ * @param ReturnShipment $shipment The shipment instance.
+ *
+ * @since 3.0.0
+ * @package Vendidero/Germanized/DHL
+ */
+ $ref = apply_filters( 'woocommerce_gzd_dhl_return_label_customer_reference', wc_gzd_dhl_get_label_reference( _x( 'Return #{shipment_id} to order {order_id}', 'dhl', 'woocommerce-germanized' ), array( '{shipment_id}' => $shipment->get_id(), '{order_id}' => $shipment->get_order_number() ) ), $label, $shipment );
+
+ return sanitize_text_field( substr( $ref, 0, 30 ) );
+}
+
+function wc_gzd_dhl_get_inlay_return_label_reference( $label, $shipment ) {
+ /**
+ * Filter to adjust the inlay return reference field placed on the DHL label. Maximum characeter length: 35.
+ *
+ * @param string $text The customer reference text.
+ * @param Label\Label $label The label instance.
+ * @param SimpleShipment $shipment The shipment instance.
+ *
+ * @since 3.0.0
+ * @package Vendidero/Germanized/DHL
+ */
+ $ref = apply_filters( 'woocommerce_gzd_dhl_inlay_return_label_reference', wc_gzd_dhl_get_label_reference( _x( 'Return shipment #{shipment_id} to order #{order_id}', 'dhl', 'woocommerce-germanized' ), array( '{shipment_id}' => $shipment->get_id(), '{order_id}' => $shipment->get_order_number() ) ), $label, $shipment );
+
+ return sanitize_text_field( substr( $ref, 0, 35 ) );
+}
+
+/**
+ * @return false|\Vendidero\Germanized\DHL\ShippingProvider\ShippingMethod
+ */
+function wc_gzd_dhl_get_current_shipping_method() {
+ $chosen_shipping_methods = WC()->session ? WC()->session->get( 'chosen_shipping_methods' ) : array();
+
+ if ( ! empty( $chosen_shipping_methods ) ) {
+ $method = wc_gzd_dhl_get_shipping_method( $chosen_shipping_methods[0] );
+
+ return $method;
+ }
+
+ return false;
+}
+
+function wc_gzd_dhl_get_international_services() {
+ return array(
+ 'Premium',
+ 'GoGreen',
+ 'AdditionalInsurance'
+ );
+}
+
+function wc_gzd_dhl_get_services() {
+ return array(
+ 'PreferredTime',
+ 'PreferredLocation',
+ 'PreferredNeighbour',
+ 'PreferredDay',
+ 'VisualCheckOfAge',
+ 'Personally',
+ 'NoNeighbourDelivery',
+ 'NamedPersonOnly',
+ 'Premium',
+ 'AdditionalInsurance',
+ 'BulkyGoods',
+ 'IdentCheck',
+ 'CashOnDelivery',
+ 'ParcelOutletRouting',
+ 'GoGreen'
+ );
+}
+
+/**
+ * @param $instance_id
+ *
+ * @return \Vendidero\Germanized\DHL\ShippingProvider\ShippingMethod
+ */
+function wc_gzd_dhl_get_shipping_method( $instance_id ) {
+ $method = wc_gzd_get_shipping_provider_method( $instance_id );
+ return new \Vendidero\Germanized\DHL\ShippingProvider\ShippingMethod( $method );
+}
+
+function wc_gzd_dhl_get_deutsche_post_shipping_method( $instance_id ) {
+ return wc_gzd_dhl_get_shipping_method( $instance_id );
+}
+
+function wc_gzd_dhl_get_preferred_services() {
+ return array(
+ 'PreferredTime',
+ 'PreferredLocation',
+ 'PreferredNeighbour',
+ 'PreferredDay',
+ );
+}
+
+function wc_gzd_dhl_get_pickup_types() {
+ return array(
+ 'packstation' => _x( 'Packstation', 'dhl', 'woocommerce-germanized' ),
+ 'postoffice' => _x( 'Postfiliale', 'dhl', 'woocommerce-germanized' ),
+ 'parcelshop' => _x( 'Postfiliale', 'dhl', 'woocommerce-germanized' )
+ );
+}
+
+function wc_gzd_dhl_is_pickup_type( $maybe_type, $type = 'packstation' ) {
+ $label = wc_gzd_dhl_get_pickup_type( $type );
+
+ if ( ! $label ) {
+ return false;
+ }
+
+ $label = strtolower( trim( $label ) );
+ $maybe_type = strtolower( trim( $maybe_type ) );
+
+ if ( strpos( $maybe_type, $label ) !== false ) {
+ return true;
+ }
+
+ return false;
+}
+
+function wc_gzd_dhl_get_excluded_working_days() {
+ $work_days = array(
+ 'mon',
+ 'tue',
+ 'wed',
+ 'thu',
+ 'fri',
+ 'sat'
+ );
+
+ $excluded = array();
+
+ foreach ( $work_days as $value ) {
+ if ( ParcelServices::is_preferred_day_excluded( $value ) ) {
+ $excluded[] = $value;
+ }
+ }
+
+ return $excluded;
+}
+
+function wc_gzd_dhl_order_has_pickup( $order ) {
+ return ParcelLocator::order_has_pickup( $order );
+}
+
+function wc_gzd_dhl_get_pickup_type( $type ) {
+ $types = wc_gzd_dhl_get_pickup_types();
+
+ if ( array_key_exists( $type, $types ) ) {
+ return $types[ $type ];
+ } elseif( in_array( $type, $types ) ) {
+ return $type;
+ } else {
+ return false;
+ }
+}
+
+/**
+ * @param WP_Error $error
+ *
+ * @return bool
+ */
+function wc_gzd_dhl_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 );
+ }
+}
+
+function wc_gzd_dhl_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;
+}
+
+function wc_gzd_dhl_format_label_state( $state, $country ) {
+ // If not USA or Australia, then change state from ISO code to name
+ if ( ! in_array( $country, array( 'US', 'AU' ) ) ) {
+
+ // Get all states for a country
+ $states = WC()->countries->get_states( $country );
+
+ // If the state is empty, it was entered as free text
+ if ( ! empty( $states ) && ! empty( $state ) ) {
+ // Change the state to be the name and not the code
+ $state = $states[ $state ];
+
+ // Remove anything in parentheses (e.g. TH)
+ $ind = strpos( $state, " (" );
+
+ if ( false !== $ind ) {
+ $state = substr( $state, 0, $ind );
+ }
+ }
+ }
+
+ return $state;
+}
+
+function wc_gzd_dhl_get_product( $the_product ) {
+ if ( ! is_a( $the_product, '\Vendidero\Germanized\DHL\Product' ) ) {
+ $product = new Product( $the_product );
+ } else {
+ $product = $the_product;
+ }
+
+ return $product;
+}
+
+/**
+ * @param Shipment $shipment
+ */
+function wc_gzd_dhl_get_label_shipment_address_addition( $shipment ) {
+ $addition = $shipment->get_address_2();
+ $street_addition = $shipment->get_address_street_addition();
+
+ if ( ! empty( $street_addition ) ) {
+ $addition = $street_addition . ( ! empty( $addition ) ? ' ' . $addition : '' );
+ }
+
+ return trim( $addition );
+}
+
+/**
+ * @param Shipment $shipment
+ *
+ * @return mixed
+ */
+function wc_gzd_dhl_get_label_shipment_street_number( $shipment ) {
+ $street_number = $shipment->get_address_street_number();
+
+ if ( ! Package::is_shipping_domestic( $shipment->get_country() ) ) {
+
+ if ( empty( $street_number ) ) {
+ /**
+ * Filter to adjust the placeholder used as street number for the DHL API in case
+ * the shipment is not domestic (inner Germnany) and a street number was not provided.
+ *
+ * @param string $placeholder The placeholder to use - default 0 as advised by DHL support.
+ *
+ * @since 3.1.0
+ * @package Vendidero/Germanized/DHL
+ */
+ $street_number = apply_filters( 'woocommerce_gzd_dhl_label_shipment_street_number_placeholder', '0' );
+ }
+ }
+
+ return $street_number;
+}
+
+/**
+ * @param \Vendidero\Germanized\DHL\Label\ReturnLabel $label
+ */
+function wc_gzd_dhl_get_return_label_sender_street_number( $label ) {
+ $street_number = $label->get_sender_street_number();
+
+ if ( ! Package::is_shipping_domestic( $label->get_sender_country() ) ) {
+ if ( empty( $street_number ) ) {
+ /**
+ * This filter is documented in includes/wc-gzd-dhl-core-functions.php
+ */
+ $street_number = apply_filters( 'woocommerce_gzd_dhl_label_shipment_street_number_placeholder', '0' );
+ }
+ }
+
+ return $street_number;
+}
+
+function wc_gzd_dhl_get_product_services( $product ) {
+ if ( in_array( $product, array_keys( wc_gzd_dhl_get_products_domestic() ) ) ) {
+ $services = wc_gzd_dhl_get_services();
+ } else {
+ $services = wc_gzd_dhl_get_international_services();
+ }
+
+ /**
+ * Warenpost does only support certain services
+ */
+ if ( 'V62WP' === $product ) {
+ $services = array_intersect( $services, array(
+ 'PreferredTime',
+ 'PreferredLocation',
+ 'PreferredNeighbour',
+ 'PreferredDay',
+ 'ParcelOutletRouting',
+ 'GoGreen'
+ ) );
+ }
+
+ return $services;
+}
+
+function wc_gzd_dhl_product_supports_service( $product, $service ) {
+ $services = wc_gzd_dhl_get_product_services( $product );
+
+ if ( ! in_array( $service, $services ) ) {
+ return false;
+ }
+
+ return true;
+}
+
+function wc_gzd_dhl_get_service_product_attributes( $service ) {
+ $products_supported = array();
+
+ foreach( array_keys( array_merge( wc_gzd_dhl_get_products_domestic(), wc_gzd_dhl_get_products_international() ) ) as $product ) {
+ if ( wc_gzd_dhl_product_supports_service( $product, $service ) ) {
+ $products_supported[] = $product;
+ }
+ }
+
+ return array(
+ 'data-products-supported' => implode( ',', $products_supported )
+ );
+}
+
+/**
+ * @param Shipment $shipment
+ *
+ * @return array
+ */
+function wc_gzd_dhl_get_deutsche_post_products( $shipment, $parent_only = true ) {
+ $country = $shipment->get_country();
+
+ if ( 'return' === $shipment->get_type() ) {
+ $country = $shipment->get_sender_country();
+ }
+
+ if ( Package::is_shipping_domestic( $country ) ) {
+ return wc_gzd_dhl_get_deutsche_post_products_domestic( $shipment, $parent_only );
+ } elseif ( Package::is_eu_shipment( $country ) ) {
+ return wc_gzd_dhl_get_deutsche_post_products_eu( $shipment, $parent_only );
+ } else {
+ return wc_gzd_dhl_get_deutsche_post_products_international( $shipment, $parent_only );
+ }
+}
+
+/**
+ * @param Shipment|false $shipment
+ *
+ * @return array
+ */
+function wc_gzd_dhl_get_deutsche_post_products_domestic( $shipment = false, $parent_only = true ) {
+ $dom = Package::get_internetmarke_api()->get_available_products( array(
+ 'product_destination' => 'national',
+ 'shipment_weight' => $shipment ? wc_gzd_dhl_get_shipment_weight( $shipment, 'g' ) : false,
+ ) );
+
+ return wc_gzd_dhl_im_get_product_list( $dom, $parent_only );
+}
+
+function wc_gzd_dhl_im_get_product_list( $products, $parent_only = true ) {
+ $list = array();
+ $additional_parent_products = array();
+
+ foreach( $products as $product ) {
+ if ( $parent_only && $product->product_parent_id > 0 ) {
+ $additional_parent_products[] = $product->product_parent_id;
+ continue;
+ }
+
+ $list[ $product->product_code ] = wc_gzd_dhl_get_im_product_title( $product->product_name );
+ }
+
+ $additional_parent_products = array_unique( $additional_parent_products );
+
+ if ( ! empty( $additional_parent_products ) ) {
+ foreach( $additional_parent_products as $product_id ) {
+ $product = Package::get_internetmarke_api()->get_product_data( $product_id );
+
+ if ( ! array_key_exists( $product->product_code, $list ) ) {
+ $list[ $product->product_code ] = wc_gzd_dhl_get_im_product_title( $product->product_name );
+ }
+ }
+ }
+
+ return $list;
+}
+
+function wc_gzd_dhl_get_deutsche_post_products_eu( $shipment = false, $parent_only = true ) {
+ $non_warenpost = Package::get_internetmarke_api()->get_available_products( array(
+ 'product_destination' => 'international',
+ 'product_is_wp_int' => 0,
+ 'shipment_weight' => $shipment ? wc_gzd_dhl_get_shipment_weight( $shipment, 'g' ) : false,
+ ) );
+
+ $warenpost = Package::get_internetmarke_api()->get_available_products( array(
+ 'product_destination' => 'eu',
+ 'product_is_wp_int' => 1,
+ 'shipment_weight' => $shipment ? wc_gzd_dhl_get_shipment_weight( $shipment, 'g' ) : false,
+ ) );
+
+ $international = array_merge( $non_warenpost, $warenpost );
+
+ return wc_gzd_dhl_im_get_product_list( $international, $parent_only );
+}
+
+/**
+ * @param Shipment|false $shipment
+ *
+ * @return array
+ */
+function wc_gzd_dhl_get_deutsche_post_products_international( $shipment = false, $parent_only = true ) {
+ if ( $shipment && Package::is_eu_shipment( $shipment->get_country() ) ) {
+ return wc_gzd_dhl_get_deutsche_post_products_eu( $shipment );
+ } else {
+ $international = Package::get_internetmarke_api()->get_available_products( array(
+ 'product_destination' => 'international',
+ 'shipment_weight' => $shipment ? wc_gzd_dhl_get_shipment_weight( $shipment, 'g' ) : false,
+ ) );
+
+ return wc_gzd_dhl_im_get_product_list( $international, $parent_only );
+ }
+}
+
+/**
+ * @param Label\DHL $label
+ * @param string $type
+ *
+ * @return mixed|string|void
+ */
+function wc_gzd_dhl_get_custom_label_format( $label, $type = '' ) {
+ $available = array(
+ 'A4',
+ '910-300-700',
+ '910-300-700-oZ',
+ '910-300-600',
+ '910-300-610',
+ '910-300-710',
+ );
+
+ /**
+ * This filter allows adjusting the default label format (GUI) to a custom format e.g. 910-300-700.
+ * The following formats are available:
+ *
+ *
+ * A4
+ * 910-300-700
+ * 910-300-700-oZ
+ * 910-300-600
+ * 910-300-610
+ * 910-300-710
+ * 100x70mm (Warenpost only)
+ *
+ *
+ * @param string $format The label format.
+ * @param Label\DHL $label The label instance.
+ * @param string $type The type e.g. inlay_return.
+ *
+ * @since 3.0.5
+ * @package Vendidero/Germanized/DHL
+ */
+ $format = apply_filters( 'woocommerce_gzd_dhl_label_custom_format', '', $label, $type );
+
+ /**
+ * Warenpost format
+ */
+ if ( 'V62WP' === $label->get_product_id() ) {
+ $available[] = '100x70mm';
+ }
+
+ if ( ! empty( $format ) && ! in_array( $format, $available ) ) {
+ $format = '';
+ }
+
+ return $format;
+}
+
+function wc_gzd_dhl_get_order( $order ) {
+ if ( is_numeric( $order ) ) {
+ $order = wc_get_order( $order);
+ }
+
+ if ( is_a( $order, 'WC_Order' ) ) {
+ try {
+ return new Vendidero\Germanized\DHL\Order( $order );
+ } catch ( Exception $e ) {
+ wc_caught_exception( $e, __FUNCTION__, func_get_args() );
+ return false;
+ }
+ }
+
+ return false;
+}
+
+function wc_gzd_dhl_get_inlay_return_products() {
+ return array(
+ 'V01PAK',
+ 'V01PRIO',
+ 'V86PARCEL',
+ 'V55PAK'
+ );
+}
+
+function wc_gzd_dhl_get_return_products_international() {
+
+ $retoure = array(
+ 'retoure_international_a' => _x( 'DHL Retoure International A', 'dhl', 'woocommerce-germanized' ),
+ 'retoure_international_b' => _x( 'DHL Retoure International B', 'dhl', 'woocommerce-germanized' ),
+ );
+
+ return $retoure;
+}
+
+function wc_gzd_dhl_get_return_products_domestic() {
+
+ $retoure = array(
+ 'retoure_online' => _x( 'DHL Retoure Online', 'dhl', 'woocommerce-germanized' ),
+ );
+
+ return $retoure;
+}
+
+function wc_gzd_dhl_get_im_product_title( $product_name ) {
+ $title = $product_name;
+
+ return $title;
+}
+
+function wc_gzd_dhl_get_products_international() {
+
+ $country = Package::get_base_country();
+
+ $germany_int = array(
+ 'V55PAK' => _x( 'DHL Paket Connect', 'dhl', 'woocommerce-germanized' ),
+ 'V54EPAK' => _x( 'DHL Europaket (B2B)', 'dhl', 'woocommerce-germanized' ),
+ 'V53WPAK' => _x( 'DHL Paket International', 'dhl', 'woocommerce-germanized' ),
+ );
+
+ $dhl_prod_int = array();
+
+ switch ( $country ) {
+ case 'DE':
+ $dhl_prod_int = $germany_int;
+ break;
+ default:
+ break;
+ }
+
+ return $dhl_prod_int;
+}
+
+function wc_gzd_dhl_get_products( $shipping_country ) {
+ if ( Package::is_shipping_domestic( $shipping_country ) ) {
+ return wc_gzd_dhl_get_products_domestic();
+ } else {
+ return wc_gzd_dhl_get_products_international();
+ }
+}
+
+function wc_gzd_dhl_get_return_products( $shipping_country ) {
+ if ( Package::is_shipping_domestic( $shipping_country ) ) {
+ return wc_gzd_dhl_get_return_products_domestic();
+ } else {
+ return wc_gzd_dhl_get_return_products_international();
+ }
+}
+
+function wc_gzd_dhl_get_return_receivers() {
+ $receivers = Package::get_return_receivers();
+ $select = array();
+
+ foreach( $receivers as $receiver ) {
+ $select[ $receiver['slug'] ] = esc_attr( $receiver['id'] ) . ' (' . ( ! empty( esc_attr( $receiver['country'] ) ) ? $receiver['country'] : '*' ) . ')';
+ }
+
+ return $select;
+}
+
+function wc_gzd_dhl_get_default_return_receiver( $country, $method = false ) {
+ return Package::get_return_receiver_by_country( $country );
+}
+
+function wc_gzd_dhl_get_default_return_receiver_slug( $country ) {
+ $receiver = Package::get_return_receiver_by_country( $country );
+
+ return ( $receiver ? $receiver['slug'] : '' );
+}
+
+function wc_gzd_dhl_get_default_product( $country, $shipment = false ) {
+ if ( Package::is_shipping_domestic( $country ) ) {
+ return Package::get_setting( 'label_default_product_dom', $shipment );
+ } else {
+ return Package::get_setting( 'label_default_product_int', $shipment );
+ }
+}
+
+function wc_gzd_dhl_get_products_domestic() {
+ $country = Package::get_base_country();
+
+ $germany_dom = array(
+ 'V01PAK' => _x( 'DHL Paket', 'dhl', 'woocommerce-germanized' ),
+ 'V01PRIO' => _x( 'DHL Paket PRIO', 'dhl', 'woocommerce-germanized' ),
+ 'V06PAK' => _x( 'DHL Paket Taggleich', 'dhl', 'woocommerce-germanized' ),
+ 'V62WP' => _x( 'DHL Warenpost', 'dhl', 'woocommerce-germanized' )
+ );
+
+ $dhl_prod_dom = array();
+
+ switch ( $country ) {
+ case 'DE':
+ $dhl_prod_dom = $germany_dom;
+ break;
+ default:
+ break;
+ }
+
+ return $dhl_prod_dom;
+}
diff --git a/packages/woocommerce-germanized-dhl/includes/wc-gzd-dhl-legacy-functions.php b/packages/woocommerce-germanized-dhl/includes/wc-gzd-dhl-legacy-functions.php
new file mode 100644
index 000000000..7d3056614
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/includes/wc-gzd-dhl-legacy-functions.php
@@ -0,0 +1,341 @@
+get_labels();
+}
+
+function wc_gzd_legacy_dhl_get_label_types() {
+ return array(
+ 'simple',
+ 'return',
+ 'deutsche_post',
+ 'deutsche_post_return'
+ );
+}
+
+function wc_gzd_dhl_get_return_label_by_shipment( $the_shipment ) {
+ return wc_gzd_dhl_get_shipment_label( $the_shipment, 'return' );
+}
+
+/**
+ * Main function for returning label.
+ *
+ * @param mixed $the_label Object or label id.
+ *
+ * @return bool|\Vendidero\Germanized\DHL\Label\Label
+ *
+ */
+function wc_gzd_dhl_get_label( $the_label = false ) {
+ return wc_gzd_get_shipment_label( $the_label );
+}
+
+function wc_gzd_dhl_get_shipment_label( $the_shipment, $type = '' ) {
+ $shipment_id = \Vendidero\Germanized\Shipments\ShipmentFactory::get_shipment_id( $the_shipment );
+
+ if ( $shipment_id ) {
+
+ $args = array(
+ 'shipment_id' => $shipment_id,
+ );
+
+ if ( ! empty( $type ) ) {
+ $args['type'] = $type;
+ }
+
+ $labels = wc_gzd_dhl_get_labels( $args );
+
+ if ( ! empty( $labels ) ) {
+ return $labels[0];
+ }
+ }
+
+ return false;
+}
+
+add_filter( 'woocommerce_gzd_shipping_provider_dhl_get_label', '_wc_gzd_dhl_legacy_shipment_label_dhl', 10, 3 );
+add_filter( 'woocommerce_gzd_shipping_provider_deutsche_post_get_label', '_wc_gzd_dhl_legacy_shipment_label_deutsche_post', 10, 3 );
+
+/**
+ * @param $label
+ * @param \Vendidero\Germanized\Shipments\Shipment $the_shipment
+ * @param \Vendidero\Germanized\Shipments\Interfaces\ShippingProvider $provider
+ *
+ * @return false|\Vendidero\Germanized\DHL\Label\Label
+ */
+function _wc_gzd_dhl_legacy_shipment_label_dhl( $label, $the_shipment, $provider ) {
+ if ( ! $label && '' === $the_shipment->get_version() ) {
+ $label_type = $the_shipment->get_type();
+
+ return wc_gzd_dhl_get_shipment_label( $the_shipment, $label_type );
+ }
+
+ return $label;
+}
+
+function _wc_gzd_dhl_legacy_shipment_label_deutsche_post( $label, $the_shipment, $provider ) {
+ if ( ! $label && '' === $the_shipment->get_version() ) {
+ $label_type = $the_shipment->get_type();
+ $label_type = 'return' === $label_type ? 'deutsche_post_return' : 'deutsche_post';
+
+ return wc_gzd_dhl_get_shipment_label( $the_shipment, $label_type );
+ }
+
+ return $label;
+}
+
+add_filter( 'woocommerce_gzd_shipment_label', '_wc_gzd_dhl_legacy_label', 10, 4 );
+
+function _wc_gzd_dhl_legacy_label( $label, $the_label, $shipping_provider, $type ) {
+ if ( ! $label ) {
+ $label_id = \Vendidero\Germanized\Shipments\Labels\Factory::get_label_id( $the_label );
+
+ if ( $label_id ) {
+ $type = WC_Data_Store::load( 'dhl-legacy-label' )->get_label_type( $label_id );
+
+ if ( $type ) {
+ $mappings = array(
+ 'simple' => '\Vendidero\Germanized\DHL\Label\DHL',
+ 'return' => '\Vendidero\Germanized\DHL\Label\DHLReturn',
+ 'deutsche_post' => '\Vendidero\Germanized\DHL\Label\DeutschePost',
+ 'deutsche_post_return' => '\Vendidero\Germanized\DHL\Label\DeutschePostReturn',
+ );
+
+ $classname = isset( $mappings[ $type ] ) ? $mappings[ $type ] : '\Vendidero\Germanized\DHL\Label\DHL';
+
+ try {
+ $label = new $classname( $label_id, true );
+ } catch( Exception $e ) {
+ wc_caught_exception( $e, __FUNCTION__, func_get_args() );
+ $label = false;
+ }
+ }
+ }
+ }
+
+ return $label;
+}
+
+function wc_gzd_dhl_get_inlay_return_label_default_args( $parent_label ) {
+ wc_deprecated_function( 'wc_gzd_dhl_get_inlay_return_label_default_args', '1.5' );
+
+ return array();
+}
+
+function wc_gzd_dhl_validate_return_label_args( $shipment, $args = array() ) {
+ wc_deprecated_function( 'wc_gzd_dhl_validate_return_label_args', '1.5' );
+
+ return $args;
+}
+
+function wc_gzd_dhl_validate_inlay_return_label_args( $parent_label, $args = array() ) {
+ wc_deprecated_function( 'wc_gzd_dhl_validate_inlay_return_label_args', '1.5' );
+
+ return $args;
+}
+
+function wc_gzd_dhl_validate_label_args( $shipment, $args = array() ) {
+ wc_deprecated_function( 'wc_gzd_dhl_validate_label_args', '1.5' );
+
+ return $args;
+}
+
+/**
+ * @param \Vendidero\Germanized\Shipments\Shipment $shipment
+ */
+function wc_gzd_dhl_shipment_needs_label( $shipment, $check_status = true ) {
+ wc_deprecated_function( 'wc_gzd_dhl_shipment_needs_label', '1.5' );
+
+ /**
+ * Filter to determine whether a shipment needs a DHL label or not.
+ *
+ * @param boolean $needs_label Whether the shipment needs a DHL label or not.
+ * @param \Vendidero\Germanized\Shipments\Shipment $shipment The shipment object.
+ *
+ * @since 3.0.0
+ * @package Vendidero/Germanized/DHL
+ */
+ return apply_filters( 'woocommerce_gzd_dhl_shipment_needs_label', $shipment->needs_label( $check_status ), $shipment );
+}
+
+/**
+ * @param \Vendidero\Germanized\DHL\Label\DHL $parent_label
+ * @param array $args
+ *
+ * @return bool|\Vendidero\Germanized\DHL\Label\DHLInlayReturn|WP_Error
+ */
+function wc_gzd_dhl_create_inlay_return_label( $parent_label, $args = array() ) {
+ wc_deprecated_function( 'wc_gzd_dhl_create_inlay_return_label', '1.5' );
+
+ $label = \Vendidero\Germanized\Shipments\Labels\Factory::get_label( 0, 'dhl', 'inlay_return' );
+ $label->set_props( $args );
+ $label->set_parent_id( $parent_label->get_id() );
+ $label->set_shipment_id( $parent_label->get_shipment_id() );
+
+ return $label;
+}
+
+function wc_gzd_dhl_update_label( $label, $args = array() ) {
+ wc_deprecated_function( 'wc_gzd_dhl_update_label', '1.5' );
+
+ return $label;
+}
+
+/**
+ * @param \Vendidero\Germanized\Shipments\Shipment $shipment the shipment
+ * @param array $args
+ */
+function wc_gzd_dhl_create_label( $shipment, $args = false ) {
+ wc_deprecated_function( 'wc_gzd_dhl_create_label', '1.5' );
+
+ try {
+ $label = $shipment->create_label( $args );
+
+ if ( is_wp_error( $label ) ) {
+ return $label;
+ }
+
+ /**
+ * Action fires after creating a DHL label.
+ *
+ * The dynamic portion of this hook, `$hook_prefix` refers to the label type e.g. return.
+ *
+ * Example hook name: woocommerce_gzd_dhl_after_create_return_label
+ *
+ * @param \Vendidero\Germanized\DHL\Label\Label $label The label object.
+ *
+ * @since 3.0.0
+ * @package Vendidero/Germanized/DHL
+ */
+ do_action( "woocommerce_gzd_dhl_after_create_label", $label );
+
+ } catch ( Exception $e ) {
+ return new WP_Error( 'error', $e->getMessage() );
+ }
+
+ return $label;
+}
+
+/**
+ * @param \Vendidero\Germanized\DHL\Order $dhl_order
+ * @param \Vendidero\Germanized\DHL\Label\ReturnLabel $shipment
+ */
+function wc_gzd_dhl_get_return_label_default_args( $dhl_order, $shipment ) {
+ wc_deprecated_function( 'wc_gzd_dhl_get_return_label_default_args', '1.5' );
+
+ return array();
+}
+
+/**
+ * @param \Vendidero\Germanized\Shipments\Shipment $shipment
+ * @param string $unit
+ *
+ * @return float
+ */
+function wc_gzd_dhl_get_shipment_weight( $shipment, $unit = 'kg', $net_weight = false ) {
+ wc_deprecated_function( 'wc_gzd_dhl_get_shipment_weight', '1.5' );
+
+ return wc_gzd_get_shipment_label_weight( $shipment, $net_weight, $unit );
+}
+
+/**
+ * @param \Vendidero\Germanized\Shipments\Shipment $shipment
+ * @param string $dimension
+ * @param string $unit
+ */
+function wc_gzd_dhl_get_shipment_dimensions( $shipment, $unit = 'cm' ) {
+ wc_deprecated_function( 'wc_gzd_dhl_get_shipment_dimensions', '1.5' );
+
+ return wc_gzd_get_shipment_label_dimensions( $shipment, $unit );
+}
+
+function wc_gzd_dhl_get_label_default_args( $dhl_order, $shipment ) {
+ wc_deprecated_function( 'wc_gzd_dhl_get_label_default_args', '1.5' );
+
+ return array();
+}
+
+function wc_gzd_dhl_get_label_id( $label ) {
+ wc_deprecated_function( 'wc_gzd_dhl_get_label_id', '1.5' );
+
+ if ( is_numeric( $label ) ) {
+ return $label;
+ } elseif ( $label instanceof Vendidero\Germanized\DHL\Label\Label ) {
+ return $label->get_id();
+ } elseif ( ! empty( $label->label_id ) ) {
+ return $label->label_id;
+ } else {
+ return false;
+ }
+}
+
+function wc_gzd_dhl_upload_data( $filename, $bits, $relative = true ) {
+ wc_deprecated_function( 'wc_gzd_dhl_upload_data', '1.5' );
+
+ return wc_gzd_shipments_upload_data( $filename, $bits, $relative );
+}
+
+function wc_gzd_dhl_get_return_label_by_parent( $label_parent_id ) {
+ wc_deprecated_function( 'wc_gzd_dhl_get_return_label_by_parent', '1.5' );
+
+ $labels = wc_gzd_dhl_get_labels( array(
+ 'parent_id' => $label_parent_id,
+ 'type' => 'return',
+ ) );
+
+ if ( ! empty( $labels ) ) {
+ return $labels[0];
+ }
+
+ return false;
+}
+
+function wc_gzd_dhl_generate_label_filename( $label, $prefix = 'label' ) {
+ wc_deprecated_function( 'wc_gzd_dhl_generate_label_filename', '1.5' );
+
+ $filename = 'dhl-' . $prefix . '-' . $label->get_shipment_id() . '.pdf';
+
+ return $filename;
+}
+
+function wc_gzd_dhl_get_deutsche_post_selected_default_product( $shipment, $dhl_order = false ) {
+ wc_deprecated_function( 'wc_gzd_dhl_get_deutsche_post_selected_default_product', '1.5' );
+
+ return array();
+}
+
+function wc_gzd_dhl_get_deutsche_post_label_default_args( $dhl_order, $shipment ) {
+ wc_deprecated_function( 'wc_gzd_dhl_get_deutsche_post_label_default_args', '1.5' );
+
+ return array();
+}
+
+function wc_gzd_dhl_validate_deutsche_post_label_args( $shipment, $args = array() ) {
+ wc_deprecated_function( 'wc_gzd_dhl_validate_deutsche_post_label_args', '1.5' );
+
+ return $args;
+}
+
+function wc_gzd_dhl_get_deutsche_post_default_product( $shipment ) {
+ wc_deprecated_function( 'wc_gzd_dhl_get_deutsche_post_default_product', '1.5' );
+
+ return false;
+}
diff --git a/packages/woocommerce-germanized-dhl/license.txt b/packages/woocommerce-germanized-dhl/license.txt
new file mode 100644
index 000000000..093879dda
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/license.txt
@@ -0,0 +1,699 @@
+WooCommerce Germanized DHL
+
+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-germanized-dhl/src/Admin/Admin.php b/packages/woocommerce-germanized-dhl/src/Admin/Admin.php
new file mode 100644
index 000000000..04d5caabb
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/Admin/Admin.php
@@ -0,0 +1,326 @@
+
+ accessed.', 'dhl', 'woocommerce-germanized' ), admin_url( 'admin.php?page=wc-status&tab=dhl' ) ) ); ?>
+ update_products();
+ $settings_url = add_query_arg( array( 'im-refresh-type' => 'products' ), Package::get_deutsche_post_shipping_provider()->get_edit_link( 'label' ) );
+
+ if ( is_wp_error( $result ) ) {
+ $settings_url = add_query_arg( array( 'error' => 1 ), $settings_url );
+ } else {
+ $settings_url = add_query_arg( array( 'success' => 1 ), $settings_url );
+ }
+
+ wp_safe_redirect( $settings_url );
+ exit();
+ }
+ } elseif ( current_user_can( 'manage_woocommerce' ) && isset( $_GET['action'], $_GET['_wpnonce'] ) && 'wc-gzd-dhl-im-page-formats-refresh' === $_GET['action'] ) {
+ if ( wp_verify_nonce( $_GET['_wpnonce'], 'wc-gzd-dhl-refresh-im-page-formats' ) ) {
+ $result = Package::get_internetmarke_api()->get_page_formats( true );
+ $settings_url = add_query_arg( array( 'im-refresh-type' => 'formats' ), Package::get_deutsche_post_shipping_provider()->get_edit_link( 'label' ) );
+
+ if ( is_wp_error( $result ) ) {
+ $settings_url = add_query_arg( array( 'error' => 1 ), $settings_url );
+ } else {
+ $settings_url = add_query_arg( array( 'success' => 1 ), $settings_url );
+ }
+
+ wp_safe_redirect( $settings_url );
+ exit();
+ }
+ }
+ }
+
+ public static function save_receiver_ids( $value, $option, $raw_value ) {
+ if ( ! isset( $option['type'] ) || 'dhl_receiver_ids' !== $option['type'] ) {
+ return $value;
+ }
+
+ $receiver = array();
+ $raw_value = is_array( $raw_value ) ? $raw_value : array();
+
+ // phpcs:disable WordPress.Security.NonceVerification.NoNonceVerification -- Nonce verification already handled in WC_Admin_Settings::save()
+ if ( isset( $raw_value['receiver_id'], $raw_value['receiver_country'] ) ) {
+
+ $receiver_ids = wc_clean( wp_unslash( $raw_value['receiver_id'] ) );
+ $countries = wc_clean( wp_unslash( $raw_value['receiver_country'] ) );
+
+ foreach ( $receiver_ids as $i => $name ) {
+ $country = isset( $countries[ $i ] ) ? substr( strtoupper( $countries[ $i ] ), 0, 2 ) : '';
+ $slug = sanitize_key( $receiver_ids[ $i ] . '_' . $country );
+
+ $receiver[ $slug ] = array(
+ 'id' => $receiver_ids[ $i ],
+ 'country' => $country,
+ 'slug' => $slug,
+ );
+ }
+ }
+
+ return $receiver;
+ }
+
+ public static function output_receiver_ids_field( $option ) {
+ ob_start();
+
+ $option_key = isset( $option['id'] ) ? $option['id'] : 'dhl_receiver_ids';
+ $receiver_ids = isset( $option['value'] ) ? $option['value'] : array();
+ ?>
+
+
+
+
+
+
+
+ ID;
+ $_product = wc_get_product( $thepostid );
+ $dhl_product = wc_gzd_dhl_get_product( $_product );
+
+ $countries = WC()->countries->get_countries();
+ $countries = array_merge( array( '0' => _x( 'Select a country', 'dhl', 'woocommerce-germanized' ) ), $countries );
+
+ woocommerce_wp_text_input( array( 'id' => '_dhl_hs_code', 'label' => _x( 'HS-Code (DHL)', 'dhl', '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.', 'dhl', 'woocommerce-germanized' ) ) );
+ woocommerce_wp_select( array( 'options' => $countries, 'id' => '_dhl_manufacture_country', 'label' => _x( 'Country of manufacture (DHL)', 'dhl', 'woocommerce-germanized' ), 'desc_tip' => true, 'description' => _x( 'The country of manufacture is needed for customs of international shipping.', 'dhl', 'woocommerce-germanized' ) ) );
+ }
+
+ public static function save_product( $product ) {
+ $hs_code = isset( $_POST['_dhl_hs_code'] ) ? wc_clean( $_POST['_dhl_hs_code'] ) : '';
+ $country = isset( $_POST['_dhl_manufacture_country'] ) ? wc_clean( $_POST['_dhl_manufacture_country'] ) : '';
+
+ $dhl_product = wc_gzd_dhl_get_product( $product );
+ $dhl_product->set_hs_code( $hs_code );
+ $dhl_product->set_manufacture_country( $country );
+ }
+
+ public static function add_template_check( $check ) {
+ $check['dhl'] = array(
+ 'title' => _x( 'DHL', 'dhl', 'woocommerce-germanized' ),
+ 'path' => Package::get_path() . '/templates',
+ 'template_path' => Package::get_template_path(),
+ 'outdated_help_url' => $check['germanized']['outdated_help_url'],
+ 'files' => array(),
+ 'has_outdated' => false,
+ );
+
+ return $check;
+ }
+
+ public static function add_legacy_meta_box() {
+ global $post;
+
+ if ( ! DHL::is_plugin_enabled() && ( $post && 'shop_order' === $post->post_type && get_post_meta( $post->ID, '_pr_shipment_dhl_label_tracking' ) ) ) {
+ add_meta_box( 'woocommerce-gzd-shipment-dhl-legacy-label', _x( 'DHL Label', 'dhl', 'woocommerce-germanized' ), array( __CLASS__, 'legacy_meta_box' ), 'shop_order', 'side', 'high' );
+ }
+ }
+
+ public static function legacy_meta_box() {
+ global $post;
+
+ $order_id = $post->ID;
+ $order = wc_get_order( $order_id );
+ $meta = $order->get_meta( '_pr_shipment_dhl_label_tracking' );
+
+ if ( ! empty( $meta ) ) {
+ echo '' . _x( 'This label has been generated by the DHL for WooCommerce Plugin and is shown for legacy purposes.', 'dhl', 'woocommerce-germanized' ) . '
';
+ echo '' . _x( 'Download label', 'dhl', 'woocommerce-germanized' ) . ' ';
+ }
+ }
+
+ public static function get_legacy_label_download_url( $order_id ) {
+ $url = add_query_arg( array( 'action' => 'wc-gzd-dhl-download-legacy-label', 'order_id' => $order_id, 'force' => 'yes' ), wp_nonce_url( admin_url(), 'dhl-download-legacy-label' ) );
+
+ return $url;
+ }
+
+ public static function download_legacy_label() {
+ if( isset( $_GET['action'] ) && 'wc-gzd-dhl-download-legacy-label' === $_GET['action'] ) {
+ if ( isset( $_GET['order_id'] ) && wp_verify_nonce( $_REQUEST['_wpnonce'], 'dhl-download-legacy-label' ) ) {
+ $order_id = absint( $_GET['order_id'] );
+ $args = \Vendidero\Germanized\Shipments\Labels\DownloadHandler::parse_args( array(
+ 'force' => wc_string_to_bool( isset( $_GET['force'] ) ? wc_clean( $_GET['force'] ) : false )
+ ) );
+
+ if ( current_user_can( 'edit_shop_orders' ) ) {
+ if ( $order = wc_get_order( $order_id ) ) {
+ $meta = (array) $order->get_meta( '_pr_shipment_dhl_label_tracking' );
+
+ if ( ! empty( $meta ) ) {
+ $path = $meta['label_path'];
+
+ if ( file_exists( $path ) ) {
+ $filename = basename( $path );
+
+ \Vendidero\Germanized\Shipments\Labels\DownloadHandler::download( $path, $filename, $args['force'] );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ 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-dhl-internetmarke', Package::get_assets_url() . '/js/admin-internetmarke' . $suffix . '.js', array( 'jquery' ), Package::get_version() );
+ wp_register_script( 'wc-gzd-admin-deutsche-post-label', Package::get_assets_url() . '/js/admin-deutsche-post-label' . $suffix . '.js', array( 'wc-gzd-admin-shipment-label-backbone' ), Package::get_version() );
+
+ if ( wp_script_is( 'wc-gzd-admin-shipment-label-backbone', 'enqueued' ) ) {
+ wp_enqueue_script( 'wc-gzd-admin-deutsche-post-label' );
+
+ wp_localize_script(
+ 'wc-gzd-admin-deutsche-post-label',
+ 'wc_gzd_admin_deutsche_post_label_params',
+ array(
+ 'refresh_label_preview_nonce' => wp_create_nonce( 'wc-gzd-dhl-refresh-deutsche-post-label-preview' ),
+ )
+ );
+ }
+
+ // Shipping zone methods
+ if ( 'woocommerce_page_wc-settings' === $screen_id && isset( $_GET['provider'] ) && 'deutsche_post' === $_GET['provider'] ) {
+ wp_enqueue_script( 'wc-gzd-admin-dhl-internetmarke' );
+ }
+ }
+
+ public static function admin_styles() {
+ global $wp_scripts;
+
+ $screen = get_current_screen();
+ $screen_id = $screen ? $screen->id : '';
+ $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
+
+ // Register admin styles.
+ wp_register_style( 'woocommerce_gzd_dhl_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() ) ) {
+ wp_enqueue_style( 'woocommerce_gzd_dhl_admin' );
+ }
+ }
+
+ protected static function get_table_screen_ids() {
+ return array(
+ 'woocommerce_page_wc-gzd-shipments',
+ 'woocommerce_page_wc-gzd-return-shipments'
+ );
+ }
+
+ public static function get_screen_ids() {
+ $screen_ids = self::get_table_screen_ids();
+
+ foreach ( wc_get_order_types() as $type ) {
+ $screen_ids[] = $type;
+ $screen_ids[] = 'edit-' . $type;
+ }
+
+ return $screen_ids;
+ }
+}
diff --git a/packages/woocommerce-germanized-dhl/src/Admin/Importer/DHL.php b/packages/woocommerce-germanized-dhl/src/Admin/Importer/DHL.php
new file mode 100644
index 000000000..c169892c8
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/Admin/Importer/DHL.php
@@ -0,0 +1,190 @@
+get_customer_number();
+ }
+
+ return ( ( ! empty( $options ) && empty( $user ) && 'yes' !== $imported && Package::base_country_is_supported() ) ? true : false );
+ }
+
+ public static function is_plugin_enabled() {
+ return class_exists( 'PR_DHL_WC' ) ? true : false;
+ }
+
+ public static function import_settings() {
+ $old_settings = (array) get_option( 'woocommerce_pr_dhl_paket_settings' );
+ $dhl = Package::get_dhl_shipping_provider();
+
+ if ( ! $dhl ) {
+ return false;
+ }
+
+ $settings_mapping = array(
+ 'account_num' => 'account_number',
+ 'participation_V01PAK' => 'participation_V01PAK',
+ 'participation_V01PRIO' => 'participation_V01PRIO',
+ 'participation_V06PAK' => 'participation_V06PAK',
+ 'participation_V55PAK' => 'participation_V55PAK',
+ 'participation_V54EPAK' => 'participation_V54EPAK',
+ 'participation_V53WPAK' => 'participation_V53WPAK',
+ 'participation_return' => 'participation_return',
+ 'api_user' => 'api_username',
+ 'api_pwd' => 'api_password',
+ 'default_product_dom' => 'label_default_product_dom',
+ 'default_product_int' => 'label_default_product_int',
+ 'default_print_codeable' => 'label_address_codeable_only',
+ 'bank_holder' => 'bank_holder',
+ 'bank_name' => 'bank_name',
+ 'bank_iban' => 'bank_iban',
+ 'bank_bic' => 'bank_bic',
+ 'bank_ref' => 'bank_ref',
+ 'bank_ref_2' => 'bank_ref_2',
+ 'preferred_day' => 'PreferredDay_enable',
+ 'preferred_day_cost' => 'PreferredDay_cost',
+ 'preferred_day_cutoff' => 'PreferredDay_cutoff_time',
+ 'preferred_exclusion_mon' => 'PreferredDay_exclusion_mon',
+ 'preferred_exclusion_tue' => 'PreferredDay_exclusion_tue',
+ 'preferred_exclusion_wed' => 'PreferredDay_exclusion_wed',
+ 'preferred_exclusion_thu' => 'PreferredDay_exclusion_thu',
+ 'preferred_exclusion_fri' => 'PreferredDay_exclusion_fri',
+ 'preferred_exclusion_sat' => 'PreferredDay_exclusion_sat',
+ 'preferred_location' => 'PreferredLocation_enable',
+ 'preferred_neighbour' => 'PreferredNeighbour_enable',
+ 'payment_gateway' => 'preferred_payment_gateways_excluded',
+ 'display_packstation' => 'parcel_pickup_packstation_enable',
+ 'display_parcelshop' => 'parcel_pickup_parcelshop_enable',
+ 'display_post_office' => 'parcel_pickup_postoffice_enable',
+ 'parcel_limit' => 'parcel_pickup_map_max_results',
+ 'google_maps_api_key' => 'parcel_pickup_map_api_password',
+ );
+
+ // Bulk update settings
+ foreach( $settings_mapping as $setting_old_key => $setting_new_key ) {
+ if ( isset( $old_settings[ 'dhl_' . $setting_old_key ] ) && ! empty( $old_settings[ 'dhl_' . $setting_old_key ] ) ) {
+ $dhl->update_setting( $setting_new_key, $old_settings[ 'dhl_' . $setting_old_key ] );
+ }
+ }
+
+ /**
+ * Default address update
+ */
+ foreach( array( 'shipper', 'return' ) as $address_type ) {
+ $plain_address = array(
+ 'company' => 'company',
+ 'address_city' => 'city',
+ 'address_zip' => 'postcode',
+ 'phone' => 'phone',
+ 'email' => 'email',
+ );
+
+ foreach( $plain_address as $prop => $new_prop ) {
+ $prop_name = $address_type . '_' . $prop;
+
+ if ( ! empty( $old_settings[ 'dhl_' . $prop_name ] ) ) {
+ update_option( "woocommerce_gzd_shipments_{$address_type}_address_{$new_prop}", $old_settings[ 'dhl_' . $prop_name ] );
+ }
+ }
+
+ if ( ! empty( $old_settings["dhl_{$address_type}_address"] ) ) {
+ $address_1 = $old_settings["dhl_{$address_type}_address"] . ' ' . ( isset( $old_settings["dhl_{$address_type}_address_no"] ) ? $old_settings["dhl_{$address_type}_address_no"] : '' );
+
+ update_option( "woocommerce_gzd_shipments_{$address_type}_address_address_1", $address_1 );
+ }
+
+ if ( ! empty( $old_settings["dhl_{$address_type}_name"] ) ) {
+ $name = explode( " ", $old_settings["dhl_{$address_type}_name"] );
+ $name_first = $name;
+ $first_name = implode( ' ', array_splice( $name_first, 0, ( sizeof( $name ) - 1 ) ) );
+ $last_name = $name[ sizeof( $name ) - 1 ];
+
+ update_option( "woocommerce_gzd_shipments_{$address_type}_address_first_name", $first_name );
+ update_option( "woocommerce_gzd_shipments_{$address_type}_address_last_name", $last_name );
+ }
+ }
+
+ // Enable maps if API key exists
+ if ( isset( $settings['dhl_google_maps_api_key'] ) && ! empty( $settings['dhl_google_maps_api_key'] ) ) {
+ $dhl->update_setting( 'parcel_pickup_map_enable', 'yes' );
+ }
+
+ // Shipper state to country ISO mapping
+ $countries = WC()->countries;
+ $shipper_country = ( isset( $old_settings['dhl_shipper_address_state'] ) && ! empty( $old_settings['dhl_shipper_address_state'] ) ) ? $old_settings['dhl_shipper_address_state'] : '';
+ $return_country = ( isset( $old_settings['dhl_return_address_state'] ) && ! empty( $old_settings['dhl_return_address_state'] ) ) ? $old_settings['dhl_return_address_state'] : '';
+ $isos = ( $countries ) ? $countries->get_countries() : array();
+
+ if ( ! empty( $shipper_country ) && ! empty( $isos ) ) {
+ if ( ( $key = array_search( $shipper_country, $isos ) ) !== false ) {
+ update_option( "woocommerce_gzd_shipments_shipper_address_country", $key );
+ }
+ }
+
+ if ( ! empty( $return_country ) && ! empty( $isos ) ) {
+ if ( ( $key = array_search( $return_country, $isos ) ) !== false ) {
+ update_option( "woocommerce_gzd_shipments_return_address_country", $key );
+ }
+ }
+
+ $dhl->save();
+
+ return true;
+ }
+
+ public static function import_order_data( $limit = 10, $offset = 0 ) {
+
+ $orders = wc_get_orders( array(
+ 'limit' => $limit,
+ 'offset' => $offset,
+ 'orderby' => 'date',
+ 'order' => 'DESC',
+ 'type' => 'shop_order'
+ ) );
+
+ if ( ! empty( $orders ) ) {
+ foreach( $orders as $order ) {
+
+ if ( ! $order->get_meta( '_shipping_address_type' ) ) {
+
+ // Update order pickup type from official DHL plugin
+ if ( self::order_has_pickup( $order ) ) {
+
+ $order->update_meta_data( '_shipping_address_type', 'dhl' );
+ $order->update_meta_data( '_shipping_dhl_postnumber', $order->get_meta( '_shipping_dhl_postnum' ) );
+
+ // Remove data to make sure we do not show data twice
+ $order->delete_meta_data( '_shipping_dhl_address_type' );
+ $order->delete_meta_data( '_shipping_dhl_postnum' );
+
+ $order->save();
+ }
+ }
+ }
+ }
+ }
+
+ protected static function order_has_pickup( $order ) {
+ $pos_ps = stripos( $order->get_shipping_address_1(), 'Packstation' );
+ $pos_fl = stripos( $order->get_shipping_address_1(), 'Postfiliale' );
+
+ if ( $pos_ps !== false || $pos_fl !== false ) {
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/packages/woocommerce-germanized-dhl/src/Admin/Importer/Internetmarke.php b/packages/woocommerce-germanized-dhl/src/Admin/Importer/Internetmarke.php
new file mode 100644
index 000000000..2704059c7
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/Admin/Importer/Internetmarke.php
@@ -0,0 +1,53 @@
+get_api_username();
+ }
+
+ return ( ( ! empty( $options ) && empty( $user ) && 'yes' !== $imported && Package::base_country_is_supported() ) ? true : false );
+ }
+
+ public static function is_plugin_enabled() {
+ return defined( 'WCDPI_PLUGIN_FILE' ) ? true : false;
+ }
+
+ public static function import_settings() {
+ $old_settings = array_merge( (array) get_option( '_wcdpi_settings_portokasse' ), (array) get_option( '_wcdpi_settings_internetmarke_1c4a' ) );
+
+ $settings_mapping = array(
+ '_wcdpi_portokasse_email' => 'api_username',
+ '_wcdpi_portokasse_password' => 'api_password',
+ );
+
+ $deutsche_post = Package::get_deutsche_post_shipping_provider();
+
+ if ( ! $deutsche_post ) {
+ return false;
+ }
+
+ // Bulk update settings
+ foreach( $settings_mapping as $setting_old_key => $setting_new_key ) {
+ if ( isset( $old_settings[ $setting_old_key ] ) ) {
+ $deutsche_post->update_setting( $setting_new_key, $old_settings[ $setting_old_key ] );
+ }
+ }
+
+ $deutsche_post->save();
+ return true;
+ }
+}
diff --git a/packages/woocommerce-germanized-dhl/src/Admin/Status.php b/packages/woocommerce-germanized-dhl/src/Admin/Status.php
new file mode 100644
index 000000000..3146b5831
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/Admin/Status.php
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ';
+ } else {
+ echo ' ' . esc_html_x( 'Unable to connect to the URL. Please make sure that your webhost allows outgoing connections to that specific URL.', 'dhl', 'woocommerce-germanized' ) . ' ';
+ }
+ ?>
+
+
+
+
+
+ hide_errors();
+ }
+
+ /**
+ *
+ */
+ public static function refresh_deutsche_post_label_preview() {
+ check_ajax_referer( 'wc-gzd-dhl-refresh-deutsche-post-label-preview', 'security' );
+
+ if ( ! current_user_can( 'edit_shop_orders' ) || ! isset( $_POST['product_id'], $_POST['shipment_id'] ) ) {
+ wp_die( -1 );
+ }
+
+ if ( ! Package::get_internetmarke_api()->is_available() ) {
+ wp_send_json( array(
+ 'success' => false,
+ 'messages' => Package::get_internetmarke_api()->get_errors()->get_error_messages(),
+ ) );
+ }
+
+ $selected_services = isset( $_POST['selected_services'] ) ? wc_clean( $_POST['selected_services'] ) : array();
+ $im_product_id = absint( $_POST['product_id'] );
+ $shipment_id = absint( $_POST['shipment_id'] );
+ $product_id = $im_product_id;
+ $is_wp_int = false;
+ $response = array(
+ 'success' => true,
+ 'preview_url' => '',
+ 'preview_data' => array(),
+ 'fragments' => array(),
+ );
+
+ if ( ! empty( $im_product_id ) ) {
+ /**
+ * Refresh im product id by selected services.
+ */
+ $im_product_id = Package::get_internetmarke_api()->get_product_code( $im_product_id, $selected_services );
+ $preview_url = Package::get_internetmarke_api()->preview_stamp( $im_product_id );
+ $preview_data = Package::get_internetmarke_api()->get_product_preview_data( $im_product_id );
+ $is_wp_int = Package::get_internetmarke_api()->is_warenpost_international( $im_product_id );
+
+ if ( $preview_url ) {
+ $response['preview_url'] = $preview_url;
+ $response['preview_data'] = $preview_data;
+ }
+ }
+
+ $response['is_wp_int'] = $is_wp_int;
+
+ if ( ( $provider = Package::get_deutsche_post_shipping_provider() ) && ( $shipment = wc_gzd_get_shipment( $shipment_id ) ) ) {
+ $fields = $provider->get_available_additional_services( $product_id, $selected_services );
+
+ $response['fragments']['#wc-gzd-shipment-label-wrapper-additional-services'] = Settings::render_label_fields( $fields, $shipment );
+ }
+
+ wp_send_json( $response );
+ }
+}
diff --git a/packages/woocommerce-germanized-dhl/src/Api/AuthSoap.php b/packages/woocommerce-germanized-dhl/src/Api/AuthSoap.php
new file mode 100644
index 000000000..f7c43b766
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/Api/AuthSoap.php
@@ -0,0 +1,65 @@
+wsdl_link = Package::get_wsdl_file( $wsdl_link );
+ }
+
+ public function get_access_token( $client_id = '', $client_secret = '' ) {
+ try {
+ $soap_client = new SoapClient( $this->wsdl_link,
+ array(
+ 'login' => Package::get_cig_user(),
+ 'password' => Package::get_cig_password(),
+ 'location' => Package::get_cig_url(),
+ 'soap_version' => SOAP_1_1,
+ 'trace' => true
+ )
+ );
+ } catch ( Exception $e ) {
+ throw $e;
+ }
+
+ if ( ! empty( $client_id ) && ! empty( $client_secret ) ) {
+ $soap_authentication = array(
+ 'user' => $client_id,
+ 'signature' => $client_secret,
+ 'type' => 0
+ );
+
+ $soap_auth_header = new SoapHeader( self::PR_DHL_HEADER_LINK, 'Authentification', $soap_authentication );
+
+ $soap_client->__setSoapHeaders( $soap_auth_header );
+ }
+
+ return $soap_client;
+ }
+}
diff --git a/packages/woocommerce-germanized-dhl/src/Api/FinderSoap.php b/packages/woocommerce-germanized-dhl/src/Api/FinderSoap.php
new file mode 100644
index 000000000..bd6f131fc
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/Api/FinderSoap.php
@@ -0,0 +1,197 @@
+get_auth_api()->get_access_token();
+ }
+
+ protected function get_translated_weekday( $number ) {
+ $weekdays = array(
+ _x( 'Monday', 'dhl', 'woocommerce-germanized' ),
+ _x( 'Tuesday', 'dhl', 'woocommerce-germanized' ),
+ _x( 'Wednesday', 'dhl', 'woocommerce-germanized' ),
+ _x( 'Thursday', 'dhl', 'woocommerce-germanized' ),
+ _x( 'Friday', 'dhl', 'woocommerce-germanized' ),
+ _x( 'Saturday', 'dhl', 'woocommerce-germanized' ),
+ _x( 'Sunday', 'dhl', 'woocommerce-germanized' ),
+ );
+
+ if ( isset( $weekdays[ $number -1 ] ) ) {
+ return $weekdays[ $number - 1 ];
+ }
+
+ return false;
+ }
+
+ public function get_parcel_location( $address, $types = array(), $limit = false ) {
+
+ $address = wp_parse_args( $address, array(
+ 'city' => '',
+ 'zip' => '',
+ 'street' => '',
+ 'streetNo' => '',
+ 'address' => '',
+ ) );
+
+ if ( ! empty( $address['address'] ) ) {
+ $parsed = wc_gzd_split_shipment_street( $address['address'] );
+
+ $address['street'] = $parsed['street'];
+ $address['streetNo'] = $parsed['number'];
+ }
+
+ $default_types = array();
+
+ if ( ParcelLocator::is_packstation_enabled() ) {
+ $default_types[] = 'packstation';
+ }
+
+ if ( ParcelLocator::is_parcelshop_enabled() ) {
+ $default_types[] = 'parcelshop';
+ }
+
+ if ( ParcelLocator::is_postoffice_enabled() ) {
+ $default_types[] = 'postoffice';
+ }
+
+ $results = array();
+ $api_results = false;
+ $this->types = empty( $types ) ? $default_types : $types;
+ $this->limit = is_numeric( $limit ) ? $limit : ParcelLocator::get_max_results();
+
+ if ( empty( $address['city'] ) && empty( $address['zip'] ) ) {
+ throw new Exception( _x( 'At least shipping city or zip is required.', 'dhl', 'woocommerce-germanized' ) );
+ }
+
+ if ( $this->types == array( 'packstation' ) ) {
+ $api_results = $this->get_packstations( $address );
+ } else {
+ $api_results = $this->get_packstations_filiale_direkt( $address );
+ }
+
+ if ( is_array( $api_results ) ) {
+ foreach( $api_results as $result ) {
+
+ // Lets assume it is a postoffice by default
+ $result->gzd_type = 'postoffice';
+ $result->gzd_id = isset( $result->depotServiceNo ) ? $result->depotServiceNo : '';
+ $result->gzd_result_id = $result->id;
+ $result->gzd_opening_hours = array();
+
+ if ( isset( $result->branchTypePF ) && 'dhlpaketshop' === $result->branchTypePF ) {
+ $result->gzd_type = 'parcelshop';
+ }
+
+ if ( isset ( $result->packstationId ) && ! empty( $result->packstationId ) ) {
+ $result->gzd_type = 'packstation';
+ $result->gzd_id = $result->packstationId;
+ }
+
+ $result->gzd_name = sprintf( _x( '%s %s', 'dhl location name', 'woocommerce-germanized' ), wc_gzd_dhl_get_pickup_type( $result->gzd_type ), $result->gzd_id );
+
+ if ( isset( $result->timeinfos ) ) {
+ foreach( $result->timeinfos->timeinfo as $time ) {
+
+ // Opening hours have type 1
+ if ( 1 !== $time->type ) {
+ continue;
+ }
+
+ if ( ! isset( $result->gzd_opening_hours[ $time->dayTo ] ) ) {
+ $result->gzd_opening_hours[ $time->dayTo ] = array(
+ 'weekday' => $this->get_translated_weekday( $time->dayTo ),
+ 'time_html' => $time->timeFrom . ' - ' . $time->timeTo,
+ );
+ } else {
+ $result->gzd_opening_hours[ $time->dayTo ]['time_html'] .= ', ' . $time->timeFrom . ' - ' . $time->timeTo;
+ }
+ }
+
+ ksort( $result->gzd_opening_hours );
+ }
+
+ // Not supporting this type
+ if ( ! in_array( $result->gzd_type, $this->types ) ) {
+ continue;
+ }
+
+ $result->html_content = wc_get_template_html( 'checkout/dhl/parcel-finder-result.php', array( 'result' => $result ) );
+
+ if ( sizeof( $results ) >= $this->limit ) {
+ break;
+ }
+
+ $results[] = $result;
+ }
+ }
+
+ return $results;
+ }
+
+ protected function get_packstations_filiale_direkt( $address ) {
+ try {
+ $soap_request = array(
+ 'address' => $address,
+ 'key' => '',
+ );
+
+ $soap_client = $this->get_access_token();
+
+ Package::log( '"getPackstationsFilialeDirektByAddress" called with: ' . print_r( $address, true ) );
+ $response_body = $soap_client->getPackstationsFilialeDirektByAddress( $soap_request );
+
+ return $response_body->packstation_filialedirekt;
+
+ } catch ( Exception $e ) {
+ Package::log( 'Response Error: ' . $e->getMessage(), 'error' );
+ throw $e;
+ }
+ }
+
+ protected function get_packstations( $address ) {
+ try {
+ $soap_request = array(
+ 'address' => $address,
+ 'key' => '',
+ );
+
+ $soap_client = $this->get_access_token();
+
+ Package::log( '"getPackstationsByAddress" called with: ' . print_r( $address, true ) );
+ $response_body = $soap_client->getPackstationsByAddress( $soap_request );
+
+ return $response_body->packstation;
+
+ } catch ( Exception $e ) {
+ Package::log( 'Response Error: ' . $e->getMessage(), 'error' );
+ throw $e;
+ }
+ }
+
+ protected function get_paketboxes() {
+
+ }
+
+ protected function get_request( $args ) {}
+}
diff --git a/packages/woocommerce-germanized-dhl/src/Api/ImProductList.php b/packages/woocommerce-germanized-dhl/src/Api/ImProductList.php
new file mode 100644
index 000000000..d62c6bd05
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/Api/ImProductList.php
@@ -0,0 +1,508 @@
+products ) ) {
+ $this->load_products();
+ }
+
+ $products = $this->products;
+
+ return $this->filter_products( $products, $filters );
+ }
+
+ protected function load_products() {
+ global $wpdb;
+
+ $products = $wpdb->get_results( "SELECT * FROM {$wpdb->gzd_dhl_im_products}" );
+
+ $this->products = $products;
+ }
+
+ public function get_default_available_products() {
+ return array(
+ '11',
+ '21',
+ '31',
+ '282',
+ '290',
+ '10246',
+ '10247',
+ '10248',
+ '10249',
+ '10254',
+ '10255',
+ '10256',
+ '10257',
+ );
+ }
+
+ protected function load_available_products() {
+ global $wpdb;
+
+ $available_products = Package::get_setting( 'deutsche_post_available_products' );
+
+ if ( empty( $available_products ) ) {
+ $available_products = $this->get_default_available_products();
+ }
+
+ if ( ! empty( $available_products ) ) {
+ $available_products = array_filter( array_map( 'absint', $available_products ) );
+ } else {
+ $available_products = array();
+ }
+
+ $available_products = array_map( function( $p ) {
+ return "'" . esc_sql( $p ) . "'";
+ }, $available_products );
+
+ $available_products = implode( ',', $available_products );
+
+ $products = $wpdb->get_results( "SELECT * FROM {$wpdb->gzd_dhl_im_products} WHERE product_code IN ($available_products)" );
+
+ $this->available_products = $products;
+ }
+
+ public function get_product_services( $product_id ) {
+ global $wpdb;
+
+ $services = array();
+ $results = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->gzd_dhl_im_product_services} WHERE product_service_product_id = %d", $product_id ) );
+
+ if ( ! empty( $results ) ) {
+ foreach( $results as $result ) {
+ $services[] = $result->product_service_slug;
+ }
+ }
+
+ return $services;
+ }
+
+ /**
+ * Returns available service slugs for a certain (parent) product.
+ *
+ * In case additional services chosen are supplied, only those services (e.g. Zusatzentgelt MBf which is only available if EINSCHREIBEN has been selected)
+ * are added which are compatible with the current selection.
+ *
+ * @param $parent_id
+ * @param array $services
+ *
+ * @return string[]
+ */
+ public function get_services_for_product( $parent_id, $services = array() ) {
+ global $wpdb;
+
+ $query = "SELECT * FROM {$wpdb->gzd_dhl_im_products}";
+ $count = 1;
+
+ if ( empty( $services ) ) {
+ $query .= " INNER JOIN {$wpdb->gzd_dhl_im_product_services} S{$count} ON {$wpdb->gzd_dhl_im_products}.product_id = S{$count}.product_service_product_id";
+ } else {
+ foreach( $services as $service ) {
+ $count++;
+
+ $query .= $wpdb->prepare( " INNER JOIN {$wpdb->gzd_dhl_im_product_services} S{$count} ON {$wpdb->gzd_dhl_im_products}.product_id = S{$count}.product_service_product_id AND S{$count}.product_service_slug = %s", $service );
+ }
+ }
+
+ $query .= $wpdb->prepare(" WHERE {$wpdb->gzd_dhl_im_products}.product_parent_id = %d", $parent_id );
+
+ if ( empty( $services ) ) {
+ $query .= $wpdb->prepare(" AND {$wpdb->gzd_dhl_im_products}.product_service_count = %d", 1 );
+ }
+
+ $results = $wpdb->get_results( $query );
+ $available_services = array();
+
+ if ( ! empty( $results ) ) {
+ foreach( $results as $result ) {
+ $product_id = $result->product_id;
+ $product_services = $wpdb->get_results( $wpdb->prepare( "SELECT product_service_slug FROM {$wpdb->gzd_dhl_im_product_services} WHERE {$wpdb->gzd_dhl_im_product_services}.product_service_product_id = %d", $product_id ) );
+
+ if ( ! empty( $product_services ) ) {
+ foreach( $product_services as $product_service ) {
+ $service_slug = $product_service->product_service_slug;
+
+ if ( ! in_array( $service_slug, $available_services ) ) {
+ $available_services[] = $service_slug;
+ }
+ }
+ }
+ }
+ }
+
+ return $available_services;
+ }
+
+ /**
+ * Returns the product id based on a list of services.
+ * In case no services are supplied, the main product is returned.
+ *
+ * @param $parent_id
+ * @param $services
+ *
+ * @return object|false
+ */
+ public function get_product_data_by_services( $parent_id, $services = array() ) {
+ global $wpdb;
+
+ $product_data = $this->get_product_data( $parent_id );
+
+ if ( empty( $product_data ) && $product_data->product_parent_id > 0 ) {
+ $parent_id = $product_data->product_parent_id;
+ }
+
+ $query = "SELECT * FROM {$wpdb->gzd_dhl_im_products}";
+ $count = 0;
+
+ if ( ! empty( $services ) ) {
+ foreach( $services as $service ) {
+ $count++;
+ $query .= $wpdb->prepare( " INNER JOIN {$wpdb->gzd_dhl_im_product_services} S{$count} ON {$wpdb->gzd_dhl_im_products}.product_id = S{$count}.product_service_product_id AND S{$count}.product_service_slug = %s", $service );
+ }
+
+ $all_services = array_map( function( $p ) {
+ return "'" . esc_sql( $p ) . "'";
+ }, $services );
+
+ $all_services = implode( ',', $all_services );
+
+ // Add a left join which must be NULL making sure that no other services are linked to that product.
+ $query .= " LEFT JOIN {$wpdb->gzd_dhl_im_product_services} S ON {$wpdb->gzd_dhl_im_products}.product_id = S.product_service_product_id AND S.product_service_slug NOT IN ($all_services)";
+ $query .= $wpdb->prepare(" WHERE {$wpdb->gzd_dhl_im_products}.product_parent_id = %d AND S.product_service_id IS NULL LIMIT 1", $parent_id );
+ } else {
+ $query .= $wpdb->prepare(" WHERE {$wpdb->gzd_dhl_im_products}.product_id = %d AND {$wpdb->gzd_dhl_im_products}.product_parent_id = %d LIMIT 1", $parent_id, 0 );
+ }
+
+ $result = $wpdb->get_row( $query );
+
+ if ( ! empty( $result ) ) {
+ return $result;
+ } else {
+ return false;
+ }
+ }
+
+ public function get_available_products( $filters = array() ) {
+ if ( is_null( $this->available_products ) ) {
+ $this->load_available_products();
+ }
+
+ $products = $this->available_products;
+
+ return $this->filter_products( $products, $filters );
+ }
+
+ protected function filter_products( $products, $filters = array() ) {
+ $shipment_weight = false;
+
+ if ( array_key_exists( 'shipment_weight', $filters ) ) {
+ $shipment_weight = $filters['shipment_weight'];
+
+ unset( $filters['shipment_weight'] );
+ }
+
+ $products = wp_list_filter( $products, $filters );
+
+ if ( false !== $shipment_weight ) {
+ foreach( $products as $key => $product ) {
+ if ( 0 !== $product->product_weight_min ) {
+ if ( $product->product_weight_min > $shipment_weight ) {
+ unset( $products[ $key ] );
+ continue;
+ }
+ }
+
+ if ( 0 !== $product->product_weight_max ) {
+ if ( $product->product_weight_max < $shipment_weight ) {
+ unset( $products[ $key ] );
+ continue;
+ }
+ }
+ }
+ }
+
+ return array_values( $products );
+ }
+
+ public function get_base_products() {
+ return self::get_products( array( 'product_parent_id' => 0 ) );
+ }
+
+ public function get_product_data_by_code( $product_code ) {
+ global $wpdb;
+
+ $product = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->gzd_dhl_im_products} WHERE product_code = %s", $product_code ) );
+
+ return $product;
+ }
+
+ public function get_product_data( $product_id ) {
+ global $wpdb;
+
+ $product = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->gzd_dhl_im_products} WHERE product_id = %d", $product_id ) );
+
+ return $product;
+ }
+
+ private function get_information_text( $stamp_type ) {
+ $information_text = '';
+
+ foreach ( $stamp_type as $stamp ) {
+ if ( $stamp->name == 'Internetmarke' ) {
+ foreach ( $stamp->propertyList as $properties ) {
+ foreach ( $properties as $property ) {
+ if ( $property->name == 'InformationText' ) {
+ $information_text = $property->propertyValue->alphanumericValue->fixValue;
+ }
+ }
+ }
+ }
+ }
+
+ return $information_text;
+ }
+
+ protected function get_dimensions( $dimensions, $type = 'width' ) {
+ $data = array(
+ "product_{$type}_min" => null,
+ "product_{$type}_max" => null,
+ "product_{$type}_unit" => null,
+ );
+
+ if ( property_exists( $dimensions, $type ) ) {
+ $d = $dimensions->{ $type };
+
+ $data["product_{$type}_min"] = property_exists( $d, 'minValue' ) ? $d->minValue : null;
+ $data["product_{$type}_max"] = property_exists( $d, 'maxValue' ) ? $d->maxValue : null;
+ $data["product_{$type}_unit"] = property_exists( $d, 'unit' ) ? $d->unit : null;
+ }
+
+ return $data;
+ }
+
+ public function get_additional_services() {
+ return array(
+ 'PRIO' => _x( 'PRIO', 'dhl', 'woocommerce-germanized' ),
+ 'ESEW' => _x( 'Einschreiben (Einwurf)', 'dhl', 'woocommerce-germanized' ),
+ 'ESCH' => _x( 'Einschreiben', 'dhl', 'woocommerce-germanized' ),
+ 'ESEH' => _x( 'Einschreiben (Eigenhändig)', 'dhl', 'woocommerce-germanized' ),
+ 'AS16' => _x( 'Alterssichtprüfung 16', 'dhl', 'woocommerce-germanized' ),
+ 'AS18' => _x( 'Alterssichtprüfung 18', 'dhl', 'woocommerce-germanized' ),
+ 'ZMBF' => _x( 'Zusatzentgelt MBf', 'dhl', 'woocommerce-germanized' ),
+ 'USFT' => _x( 'Unterschrift', 'dhl', 'woocommerce-germanized' ),
+ 'TRCK' => _x( 'Tracked', 'dhl', 'woocommerce-germanized' ),
+ );
+ }
+
+ public function get_additional_service_title( $service ) {
+ $services = $this->get_additional_services();
+
+ return array_key_exists( $service, $services ) ? $services[ $service ] : '';
+ }
+
+ protected function get_additional_service_identifiers() {
+ return array(
+ '+ einschreiben einwurf' => 'ESEW',
+ '+ einschreiben + einwurf' => 'ESEW',
+ '+ einschreiben + eigenhändig' => 'ESEH',
+ '+ einschreiben' => 'ESCH',
+ '+ zusatzentgelt mbf' => 'ZMBF',
+ '+ prio' => 'PRIO',
+ 'unterschrift' => 'USFT',
+ 'tracked' => 'TRCK',
+ );
+ }
+
+ protected function is_additional_service( $slug ) {
+ $service_slug = $this->get_product_service_slugs( $slug );
+
+ return ! empty( $service_slug ) ? true : false;
+ }
+
+ protected function get_product_base_slug( $slug ) {
+ $additional_services = $this->get_additional_service_identifiers();
+ $slug = str_replace( 'integral', '', $slug );
+
+ foreach( array_keys( $additional_services ) as $identifier ) {
+ $slug = str_replace( $identifier, ' ', $slug );
+ }
+
+ return $this->sanitize_product_slug( $slug );
+ }
+
+ protected function get_product_service_slugs( $slug ) {
+ $service_slugs = array();
+ $has_einschreiben = false;
+
+ foreach( $this->get_additional_service_identifiers() as $identifier => $service ) {
+ if ( strpos( $slug, $identifier ) !== false ) {
+ if ( strpos( $identifier, 'einschreiben' ) !== false ) {
+ if ( ! $has_einschreiben ) {
+ $has_einschreiben = true;
+ $service_slugs[] = $service;
+ }
+ } elseif( strpos( $slug, $identifier ) !== false ) {
+ $service_slugs[] = $service;
+ }
+ }
+ }
+
+ return array_unique( $service_slugs );
+ }
+
+ protected function sanitize_product_slug( $product_name ) {
+ $product_name = trim( mb_strtolower( $product_name ) );
+
+ // Remove duplicate whitespaces
+ $product_name = preg_replace( '/\s+/', ' ', $product_name );
+
+ return $product_name;
+ }
+
+ public function update() {
+ global $wpdb;
+
+ $result = new \WP_Error();
+
+ try {
+ $product_soap = new ImProductsSoap( array(), Package::get_wsdl_file( Package::get_internetmarke_products_url() ) );
+ $product_list = $product_soap->getProducts();
+
+ $wpdb->query( "TRUNCATE TABLE {$wpdb->gzd_dhl_im_products}" );
+ $wpdb->query( "TRUNCATE TABLE {$wpdb->gzd_dhl_im_product_services}" );
+
+ $products = array(
+ 'sales' => $product_list->Response->salesProductList->SalesProduct,
+ 'additional' => $product_list->Response->additionalProductList->AdditionalProduct,
+ 'basic' => $product_list->Response->basicProductList->BasicProduct
+ );
+
+ $products_with_additional_service = array();
+
+ foreach( $products as $product_type => $inner_products ) {
+ foreach( $inner_products as $product ) {
+
+ $extended_identifier = $product->extendedIdentifier;
+ $extern_identifier = property_exists( $extended_identifier, 'externIdentifier' ) ? $extended_identifier->externIdentifier[0] : new \stdClass();
+
+ if ( ! property_exists( $extern_identifier, 'id' ) || empty( $extern_identifier->id ) ) {
+ continue;
+ }
+
+ $to_insert = array(
+ 'product_im_id' => $extended_identifier->{'ProdWS-ID'},
+ 'product_code' => property_exists( $extern_identifier, 'id' ) ? $extern_identifier->id : $extended_identifier->{'ProdWS-ID'},
+ 'product_name' => property_exists( $extern_identifier, 'name' ) ? $extern_identifier->name : $extended_identifier->name,
+ 'product_type' => $product_type,
+ 'product_annotation' => property_exists( $extended_identifier, 'annotation' ) ? $extended_identifier->annotation : '',
+ 'product_description' => property_exists( $extended_identifier, 'description' ) ? $extended_identifier->description : '',
+ 'product_destination' => $extended_identifier->destination,
+ 'product_price' => property_exists( $product->priceDefinition, 'price' ) ? Package::eur_to_cents( $product->priceDefinition->price->calculatedGrossPrice->value ) : Package::eur_to_cents( $product->priceDefinition->grossPrice->value ),
+ 'product_information_text' => property_exists( $product, 'stampTypeList' ) ? $this->get_information_text( (array) $product->stampTypeList->stampType ) : '',
+ 'product_is_wp_int' => false,
+ );
+
+ $product_slug = $this->sanitize_product_slug( $to_insert['product_name'] );
+
+ /**
+ * Exclude national Warenpost as this service won't be available
+ * in the future (only via DHL).
+ */
+ if ( strpos( $product_slug, 'warenpost' ) !== false && 'international' !== $to_insert['product_destination'] ) {
+ continue;
+ }
+
+ /**
+ * Warenpost International
+ */
+ if ( strpos( $product_slug, 'warenpost' ) !== false ) {
+ $to_insert['product_is_wp_int'] = 1;
+ }
+
+ /**
+ * EU Warenpost
+ */
+ if ( strpos( $product_slug, 'warenpost' ) !== false && strpos( $product_slug, '(eu' ) !== false ) {
+ $to_insert['product_destination'] = 'eu';
+ }
+
+ if ( property_exists( $product, 'dimensionList' ) ) {
+ $dimensions = $product->dimensionList;
+
+ $to_insert = array_merge( $to_insert, $this->get_dimensions( $dimensions, 'width' ) );
+ $to_insert = array_merge( $to_insert, $this->get_dimensions( $dimensions, 'height' ) );
+ $to_insert = array_merge( $to_insert, $this->get_dimensions( $dimensions, 'length' ) );
+ }
+
+ if ( property_exists( $product, 'weight' ) ) {
+ $to_insert = array_merge( $to_insert, $this->get_dimensions( $product, 'weight' ) );
+ }
+
+ $to_insert['product_slug'] = $this->sanitize_product_slug( $to_insert['product_name'] );
+
+ $to_insert = array_map( 'wc_clean', $to_insert );
+
+ /**
+ * Skip product creation if this is an additional service
+ */
+ if ( $this->is_additional_service( $to_insert['product_slug'] ) ) {
+ $products_with_additional_service[] = $to_insert;
+
+ continue;
+ }
+
+ $wpdb->insert( $wpdb->gzd_dhl_im_products, $to_insert );
+ }
+ }
+
+ foreach( $products_with_additional_service as $product_to_insert ) {
+ $product_base_slug = $this->get_product_base_slug( $product_to_insert['product_slug'] );
+ $parent_product = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->gzd_dhl_im_products} WHERE product_slug = %s", $product_base_slug ) );
+ $service_slugs = $this->get_product_service_slugs( $product_to_insert['product_slug'] );
+
+ if ( ! empty( $parent_product ) && ! empty( $service_slugs ) ) {
+ $product_to_insert['product_parent_id'] = $parent_product->product_id;
+ $product_to_insert['product_service_count'] = sizeof( $service_slugs );
+ }
+
+ $wpdb->insert( $wpdb->gzd_dhl_im_products, $product_to_insert );
+
+ $product_id = $wpdb->insert_id;
+
+ if ( $product_id && ! empty( $parent_product ) && ! empty( $service_slugs ) ) {
+ foreach( $service_slugs as $service_slug ) {
+ $service_insert = array(
+ 'product_service_product_id' => $product_id,
+ 'product_service_product_parent_id' => $parent_product->product_id,
+ 'product_service_slug' => $service_slug,
+ );
+
+ $wpdb->insert( $wpdb->gzd_dhl_im_product_services, $service_insert );
+ }
+ }
+ }
+
+ } catch( \Exception $e ) {
+ $result->add( 'soap', $e->getMessage() );
+ }
+
+ return wc_gzd_dhl_wp_error_has_errors( $result ) ? $result : true;
+ }
+}
diff --git a/packages/woocommerce-germanized-dhl/src/Api/ImProductsSoap.php b/packages/woocommerce-germanized-dhl/src/Api/ImProductsSoap.php
new file mode 100644
index 000000000..4dfdecc67
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/Api/ImProductsSoap.php
@@ -0,0 +1,40 @@
+ SOAP_SINGLE_ELEMENT_ARRAYS ), $options );
+
+ if ( $wsdl === null ) {
+ $wsdl = Package::get_internetmarke_products_url();
+ }
+
+ parent::__construct( $wsdl, $options );
+
+ $this->__setSoapHeaders( $this->get_headers() );
+ }
+
+ protected function get_headers() {
+ return WsSecurity::createWsSecuritySoapHeader( Package::get_internetmarke_product_username(), Package::get_internetmarke_product_password() );
+ }
+
+ public function getProducts( $dedicatedProducts = 1 ) {
+ return $this->__soapCall(
+ 'getProductList',
+ array(
+ 'getProductListRequest' => array(
+ 'mandantID' => Package::get_internetmarke_product_mandant_id(),
+ 'dedicatedProducts' => $dedicatedProducts,
+ 'responseMode' => 0
+ )
+ )
+ );
+ }
+}
diff --git a/packages/woocommerce-germanized-dhl/src/Api/ImRefundSoap.php b/packages/woocommerce-germanized-dhl/src/Api/ImRefundSoap.php
new file mode 100644
index 000000000..72531784a
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/Api/ImRefundSoap.php
@@ -0,0 +1,93 @@
+partner_information = $partner_information;
+ $options = array_merge( array( 'features' => SOAP_SINGLE_ELEMENT_ARRAYS ), $options );
+
+ if ( $wsdl === null ) {
+ $wsdl = Package::get_internetmarke_refund_url();
+ }
+
+ parent::__construct( $wsdl, $options );
+
+ $this->__setSoapHeaders( $this->partner_information->soapHeaderArray() );
+ }
+
+ /**
+ * Authenticate user request.
+ *
+ * @return User
+ */
+ public function authenticateUser( $username, $password ) {
+ $result = $this->__soapCall( 'authenticateUser', array(
+ 'AuthenticateUserRequest' => array(
+ 'username' => $username,
+ 'password' => $password
+ )
+ ) );
+
+ return User::fromStdObject( $result );
+ }
+
+ /**
+ * Return retoure id.
+ *
+ * @return int
+ */
+ public function createRetoureId() {
+ $result = $this->__soapCall( 'createRetoureId', array(
+ 'CreateRetoureIdRequest' => ''
+ ) );
+
+ return $result->shopRetoureId;
+ }
+
+ /**
+ * Retoure/refund selected shipping labels.
+ *
+ * @param $user_token
+ * @param $shop_retoure_id
+ * @param $shop_retoure_id
+ * @param $voucher_set
+ *
+ * @return int
+ */
+ public function retoureVouchers( $user_token, $shop_retoure_id, $shop_order_id, $voucher_set = array() ) {
+ $data = array(
+ 'RetoureVouchersRequest' => array(
+ 'userToken' => $user_token,
+ 'shopRetoureId' => $shop_retoure_id,
+ 'shoppingCart' => array(
+ 'shopOrderId' => $shop_order_id
+ )
+ )
+ );
+
+ if ( ! empty( $voucher_set ) ) {
+ $data['RetoureVouchersRequest']['shoppingCart']['voucherSet'] = array();
+
+ foreach ( $voucher_set as $voucher_no ) {
+ $data['RetoureVouchersRequest']['shoppingCart']['voucherSet']['voucherNo'] = $voucher_no;
+ }
+ }
+
+ $result = $this->__soapCall('retoureVouchers', $data );
+
+ return $result->retoureTransactionId;
+ }
+}
diff --git a/packages/woocommerce-germanized-dhl/src/Api/ImWarenpostIntRest.php b/packages/woocommerce-germanized-dhl/src/Api/ImWarenpostIntRest.php
new file mode 100644
index 000000000..d8fdc976b
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/Api/ImWarenpostIntRest.php
@@ -0,0 +1,369 @@
+get_request( '/dpi/shipping/v1/shipments/' . $awb . '/itemlabels', array(), 'pdf' );
+
+ return $pdf;
+ }
+
+ /**
+ * Updates the label
+ *
+ * @param DeutschePost $label
+ * @param \stdClass $result
+ *
+ * @throws Exception
+ */
+ public function update_label( &$label, $result ) {
+ $order_id = wc_clean( $result->orderId );
+ $awb = wc_clean( $result->shipments[0]->awb );
+ $barcode = wc_clean( $result->shipments[0]->items[0]->barcode );
+ $pdf = $this->get_pdf( $awb );
+
+ if ( ! $pdf ) {
+ throw new Exception( _x( 'Error while fetching label PDF', 'dhl', 'woocommerce-germanized' ) );
+ }
+
+ if ( $path = $label->upload_label_file( $pdf ) ) {
+ $label->set_path( $path );
+ } else {
+ throw new Exception( _x( 'Error while fetching label PDF', 'dhl', 'woocommerce-germanized' ) );
+ }
+
+ $label->set_shop_order_id( $order_id );
+ $label->set_wp_int_awb( $awb );
+ $label->set_wp_int_barcode( $barcode );
+ $label->set_number( $barcode );
+
+ $label->save();
+
+ return $label;
+ }
+
+ /**
+ * Creates a new order based on the given data
+ *
+ * @see https://api-qa.deutschepost.com/dpi-apidoc/index_prod_v1.html#/reference/orders/create-order/create-order
+ *
+ * @param DeutschePost $label
+ *
+ * @throws Exception
+ */
+ public function create_label( &$label ) {
+
+ if ( ! $shipment = $label->get_shipment() ) {
+ throw new Exception( _x( 'Missing shipment', 'dhl', 'woocommerce-germanized' ) );
+ }
+
+ $customs_data = wc_gzd_dhl_get_shipment_customs_data( $label, 33 );
+ $positions = array();
+ $position_index = 0;
+ $total_value = 0;
+ $total_net_weight = 0;
+
+ foreach( $customs_data['items'] as $position ) {
+ /**
+ * The Warenpost API expects value and weight to be a per row value, e.g.
+ * if 2x Product A is included the total weight/value is expected. In contrarian to the DHL customs API.
+ */
+ $pos_net_weight = intval( wc_get_weight( $position['weight_in_kg'], 'g', 'kg' ) );
+ $total_value += $position['value'];
+ $total_net_weight += $pos_net_weight;
+
+ array_push($positions, array(
+ 'contentPieceIndexNumber' => $position_index++,
+ 'contentPieceHsCode' => $position['tariff_number'],
+ 'contentPieceDescription' => $position['description'],
+ 'contentPieceValue' => $position['value'],
+ 'contentPieceNetweight' => $pos_net_weight,
+ 'contentPieceOrigin' => $position['origin_code'],
+ 'contentPieceAmount' => $position['quantity']
+ ) );
+ }
+
+ $is_return = 'return' === $label->get_type();
+
+ if ( $is_return ) {
+ $sender_name = ( $shipment->get_sender_company() ? $shipment->get_sender_company() . ' ' : '' ) . $shipment->get_formatted_sender_full_name();
+ } else {
+ $sender_name = ( Package::get_setting( 'shipper_company' ) ? Package::get_setting( 'shipper_company' ) . ' ' : '' ) . Package::get_setting( 'shipper_name' );
+ }
+
+ $recipient = $shipment->get_company() ? $shipment->get_company() . ', ' : '' . $shipment->get_formatted_full_name();
+
+ $request_data = array(
+ 'customerEkp' => $this->get_ekp(),
+ 'orderId' => null,
+ 'items' => array(
+ array(
+ 'id' => 0,
+ 'product' => $label->get_product_id(),
+ 'serviceLevel' => apply_filters( 'woocommerce_gzd_deutsche_post_label_api_customs_shipment_service_level', 'STANDARD', $label ),
+ 'recipient' => $recipient,
+ 'recipientPhone' => $shipment->get_phone(),
+ 'recipientEmail' => $shipment->get_email(),
+ 'addressLine1' => $shipment->get_address_1(),
+ 'addressLine2' => $shipment->get_address_2(),
+ 'city' => $shipment->get_city(),
+ 'state' => wc_gzd_dhl_format_label_state( $shipment->get_state(), $shipment->get_country() ),
+ 'postalCode' => $shipment->get_postcode(),
+ 'destinationCountry' => $shipment->get_country(),
+ 'shipmentAmount' => wc_format_decimal( $shipment->get_total() + $shipment->get_additional_total(), 2 ),
+ 'shipmentCurrency' => get_woocommerce_currency(),
+ 'shipmentGrossWeight' => wc_get_weight( $label->get_weight(), 'g', 'kg' ),
+ 'senderName' => $sender_name,
+ 'senderAddressLine1' => $is_return ? $shipment->get_sender_address_1() : Package::get_setting( 'shipper_address' ),
+ 'senderAddressLine2' => $is_return ? $shipment->get_sender_address_2() : '',
+ 'senderCountry' => $is_return ? $shipment->get_sender_country() : Package::get_setting( 'shipper_country' ),
+ 'senderCity' => $is_return ? $shipment->get_sender_city() : Package::get_setting( 'shipper_city' ),
+ 'senderPostalCode' => $is_return ? $shipment->get_sender_postcode() : Package::get_setting( 'shipper_postcode' ),
+ 'senderPhone' => $is_return ? $shipment->get_sender_phone() : Package::get_setting( 'shipper_phone' ),
+ 'senderEmail' => $is_return ? $shipment->get_sender_email() : Package::get_setting( 'shipper_email' ),
+ 'returnItemWanted' => false,
+ 'shipmentNaturetype' => strtoupper( apply_filters( 'woocommerce_gzd_deutsche_post_label_api_customs_shipment_nature_type', ( $is_return ? 'RETURN_GOODS' : 'SALE_GOODS' ), $label ) ),
+ 'contents' => array()
+ )
+ ),
+ 'orderStatus' => 'FINALIZE',
+ 'paperwork' => array(
+ 'contactName' => $sender_name,
+ 'awbCopyCount' => 1,
+ 'jobReference' => null,
+ 'pickupType' => 'CUSTOMER_DROP_OFF',
+ 'pickupLocation' => null,
+ 'pickupDate' => null,
+ 'pickupTimeSlot' => null,
+ 'telephoneNumber' => null
+ )
+ );
+
+ // Do only add customs data in case it is a non-EU shipment
+ if ( Package::is_crossborder_shipment( $shipment->get_country() ) ) {
+ $request_data['items'][0]['contents'] = $positions;
+
+ /**
+ * If the total position net weight and/or value is greater than the global shipment value
+ * use the position value instead.
+ */
+ if ( $total_net_weight > $request_data['items'][0]['shipmentGrossWeight'] ) {
+ $request_data['items'][0]['shipmentGrossWeight'] = $total_net_weight;
+ }
+
+ if ( $total_value > $request_data['items'][0]['shipmentAmount'] ) {
+ $request_data['items'][0]['shipmentAmount'] = $total_value;
+ }
+ }
+
+ $transmit_data = wc_string_to_bool( Package::get_setting( 'label_force_email_transfer' ) );
+
+ if ( $dhl_order = wc_gzd_dhl_get_order( $shipment->get_order() ) ) {
+ $transmit_data = $dhl_order->supports_email_notification();
+ }
+
+ if ( ! apply_filters( 'woocommerce_gzd_deutsche_post_label_api_customs_transmit_communication_data', $transmit_data, $label ) ) {
+ if ( $is_return ) {
+ $request_data['senderPhone'] = '';
+ $request_data['senderEmail'] = '';
+ } else {
+ $request_data['recipientPhone'] = '';
+ $request_data['recipientEmail'] = '';
+ }
+ }
+
+ $request_data = $this->walk_recursive_remove( $request_data );
+ $result = $this->post_request( '/dpi/shipping/v1/orders', json_encode( $request_data, JSON_PRETTY_PRINT ) );
+
+ if ( isset( $result->shipments ) ) {
+ return $this->update_label( $label, $result );
+ } else {
+ throw new Exception( _x( 'Invalid API response', 'dhl', 'woocommerce-germanized' ) );
+ }
+ }
+
+ protected function get_user_token() {
+ $user_token = false;
+
+ if ( get_transient( 'woocommerce_gzd_im_wp_int_user_token' ) ) {
+ $user_token = get_transient( 'woocommerce_gzd_im_wp_int_user_token' );
+ } else {
+ $response_body = $this->get_request( '/v1/auth/accesstoken', array(), 'xml' );
+
+ $reg_exp_ut = "/(.+?)<\/userToken>/";
+
+ if ( preg_match( $reg_exp_ut, $response_body, $match_ut ) ) {
+ $user_token = $match_ut[1];
+
+ set_transient( 'woocommerce_gzd_im_wp_int_user_token', $user_token, ( MINUTE_IN_SECONDS * 3 ) );
+ }
+ }
+
+ if ( ! $user_token ) {
+ throw new Exception( _x( 'Error while authenticating user.', 'dhl', 'woocommerce-germanized' ) );
+ }
+
+ return $user_token;
+ }
+
+ protected function is_sandbox() {
+ return Package::is_debug_mode() && defined( 'WC_GZD_DHL_IM_WP_SANDBOX_USER' );
+ }
+
+ protected function get_auth() {
+ return $this->get_basic_auth_encode( Package::get_internetmarke_warenpost_int_username(), Package::get_internetmarke_warenpost_int_password() );
+ }
+
+ /**
+ * Could be either:
+ *
+ * - application/pdf (A6)
+ * - application/pdf+singlepage (A6)
+ * - application/pdf+singlepage+6x4 (6x4 inch)
+ * - application/zpl (A6)
+ * - application/zpl+rotated (rotated by 90 degrees for label printers)
+ * - application/zpl+6x4 (6x4 inch)
+ * - application/zpl+rotated+6x4 (6x4 inch and rotated by 90 degrees for label printers)
+ *
+ * @return string
+ */
+ protected function get_pdf_accept_header() {
+ return apply_filters( 'woocommerce_gzd_deutsche_post_label_api_pdf_accept_header', 'application/pdf' );
+ }
+
+ protected function set_header( $authorization = '', $request_type = 'GET', $endpoint = '' ) {
+ if ( '/v1/auth/accesstoken' !== $endpoint ) {
+ $token = $this->get_user_token();
+ $authorization = $token;
+ }
+
+ parent::set_header( $authorization );
+
+ /**
+ * Add PDF header to make sure we are receiving the right file type from DP API
+ */
+ if ( strpos( $endpoint, 'itemlabels' ) !== false ) {
+ $this->remote_header['Accept'] = $this->get_pdf_accept_header();
+ }
+
+ $date = new \DateTime( "now", new \DateTimeZone( 'Europe/Berlin' ) );
+
+ $this->remote_header = array_merge( $this->remote_header, array(
+ 'KEY_PHASE' => $this->get_key_phase(),
+ 'PARTNER_ID' => $this->get_partner_id(),
+ 'REQUEST_TIMESTAMP' => $date->format( 'dmY-His' ),
+ 'PARTNER_SIGNATURE' => $this->get_signature( $date ),
+ ) );
+ }
+
+ protected function get_ekp() {
+ return Package::get_internetmarke_warenpost_int_ekp();
+ }
+
+ protected function walk_recursive_remove( array $array ) {
+ foreach ( $array as $k => $v ) {
+
+ if ( is_array( $v ) ) {
+ $array[ $k ] = $this->walk_recursive_remove( $v );
+ }
+
+ // Explicitly allow street_number fields to equal 0
+ if ( '' === $v || is_null( $v ) ) {
+ unset( $array[ $k ] );
+ }
+ }
+
+ return $array;
+ }
+
+ protected function get_basic_auth_encode( $user, $pass ) {
+ $pass = htmlentities( $pass, ENT_XML1 );
+
+ return base64_encode( $user . ':' . $pass );
+ }
+
+ protected function handle_get_response( $response_code, $response_body ) {
+ switch ( $response_code ) {
+ case '200':
+ case '201':
+ break;
+ default:
+ throw new Exception( _x( 'Error during Warenpost International request.', 'dhl', 'woocommerce-germanized' ) );
+ }
+ }
+
+ protected function handle_post_response( $response_code, $response_body ) {
+ switch ( $response_code ) {
+ case '200':
+ case '201':
+ break;
+ default:
+ $error_message = '';
+
+ if ( isset( $response_body->messages ) ) {
+ foreach( $response_body->messages as $message ) {
+ $error_message .= ( ! empty( $error_message ) ? ', ' : '' ) . $message;
+ }
+ }
+
+ if ( empty( $error_message ) ) {
+ $error_message = $response_code;
+ }
+
+ throw new Exception( sprintf( _x( 'Error during request: %s', 'dhl', 'woocommerce-germanized' ), $error_message ) );
+ }
+ }
+
+ protected function get_partner_id() {
+ return $this->is_sandbox() ? 'DP_LT' : Package::get_internetmarke_partner_id();
+ }
+
+ protected function get_key_phase() {
+ return $this->is_sandbox() ? 1 : Package::get_internetmarke_key_phase();
+ }
+
+ protected function get_partner_token() {
+ return Package::get_internetmarke_token();
+ }
+
+ protected function get_signature( $date = null ) {
+ if ( ! $date ) {
+ $date = new \DateTime( "now", new \DateTimeZone( 'Europe/Berlin' ) );
+ }
+
+ return substr(
+ md5(
+ join(
+ '::',
+ array(
+ $this->get_partner_id(),
+ $date->format('dmY-His'),
+ $this->get_key_phase(),
+ $this->get_partner_token()
+ )
+ )
+ ),
+ 0,
+ 8
+ );
+ }
+}
diff --git a/packages/woocommerce-germanized-dhl/src/Api/Internetmarke.php b/packages/woocommerce-germanized-dhl/src/Api/Internetmarke.php
new file mode 100644
index 000000000..52fb4d34c
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/Api/Internetmarke.php
@@ -0,0 +1,831 @@
+partner = new PartnerInformation( Package::get_internetmarke_partner_id(), Package::get_internetmarke_key_phase(), Package::get_internetmarke_token() );
+ $this->errors = new \WP_Error();
+
+ try {
+ if ( ! Package::has_load_dependencies() ) {
+ throw new \Exception( sprintf( _x( 'To enable communication between your shop and DHL, the PHP SOAPClient is required. Please contact your host and make sure that SOAPClient is installed .', 'dhl', 'woocommerce-germanize-dhl' ), 'https://www.php.net/manual/class.soapclient.php', admin_url( 'admin.php?page=wc-status' ) ) );
+ }
+
+ $this->api = new Service( $this->partner, array(), Package::get_wsdl_file( Package::get_internetmarke_main_url() ) );
+ } catch( \Exception $e ) {
+ $this->errors->add( 'startup', sprintf( _x( 'Error while instantiating main Internetmarke API: %s', 'dhl', 'woocommerce-germanized' ), $e->getMessage() ) );
+ }
+
+ if ( ! Package::is_deutsche_post_enabled() ) {
+ $this->errors->add( 'startup', _x( 'Internetmarke is disabled. Please enable Internetmarke.', 'dhl', 'woocommerce-germanized' ) );
+ }
+ }
+
+ public function is_configured() {
+ return Package::get_internetmarke_username() && Package::get_internetmarke_password();
+ }
+
+ public function auth() {
+ if ( $this->is_configured() && ! $this->has_startup_error() ) {
+ try {
+ $this->errors->remove( 'authentication' );
+
+ $this->user = $this->api->authenticateUser( Package::get_internetmarke_username(), Package::get_internetmarke_password() );
+ } catch( \Exception $e ) {
+ $this->errors->add( 'authentication', _x( 'Wrong username or password', 'dhl', 'woocommerce-germanized' ) );
+ }
+ }
+
+ if ( ! $this->has_authentication_error() ) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public function has_authentication_error() {
+ $errors = $this->errors->get_error_message( 'authentication' );
+
+ return empty( $errors ) ? false : true;
+ }
+
+ public function get_authentication_error() {
+ $error = $this->errors->get_error_message( 'authentication' );
+
+ return $error;
+ }
+
+ public function has_startup_error() {
+ $errors = $this->errors->get_error_message( 'startup' );
+
+ return empty( $errors ) ? false : true;
+ }
+
+ public function get_startup_error() {
+ $error = $this->errors->get_error_message( 'startup' );
+
+ return $error;
+ }
+
+ public function has_errors() {
+ return wc_gzd_dhl_wp_error_has_errors( $this->errors ) ? true : false;
+ }
+
+ public function get_errors() {
+ return wc_gzd_dhl_wp_error_has_errors( $this->errors ) ? $this->errors : false;
+ }
+
+ public function is_available() {
+ return ! $this->has_authentication_error() && ! $this->has_startup_error() && is_a( $this->api, '\baltpeter\Internetmarke\Service' );
+ }
+
+ public function get_user() {
+ if ( ! $this->user ) {
+ $this->auth();
+ }
+
+ if ( $this->user ) {
+ return $this->user;
+ } else {
+ return false;
+ }
+ }
+
+ public function get_balance( $force_refresh = false ) {
+ $balance = get_transient( 'wc_gzd_dhl_portokasse_balance' );
+
+ if ( ! $balance || $force_refresh ) {
+ if ( $user = $this->get_user() ) {
+ $balance = $user->getWalletBalance();
+
+ set_transient( 'wc_gzd_dhl_portokasse_balance', $user->getWalletBalance(), HOUR_IN_SECONDS );
+ } else {
+ $balance = 0;
+ }
+ }
+
+ return $balance;
+ }
+
+ protected function invalidate_balance() {
+ delete_transient( 'wc_gzd_dhl_portokasse_balance' );
+ }
+
+ public function reload_products() {
+ $this->products = null;
+ }
+
+ protected function load_products() {
+ if ( is_null( $this->products ) ) {
+ $this->products = new ImProductList();
+ }
+
+ $transient = get_transient( 'wc_gzd_dhl_im_products_expire' );
+
+ if ( ! $transient ) {
+ $result = $this->products->update();
+
+ if ( is_wp_error( $result ) ) {
+ Package::log( 'Error while refreshing Internetmarke product data: ' . $result->get_error_message() );
+ }
+
+ /**
+ * Refresh product data once per day.
+ */
+ set_transient( 'wc_gzd_dhl_im_products_expire', DAY_IN_SECONDS );
+ }
+ }
+
+ public function get_products( $filters = array() ) {
+ $this->load_products();
+
+ return $this->products->get_products( $filters );
+ }
+
+ public function get_base_products() {
+ $this->load_products();
+
+ return $this->products->get_base_products();
+ }
+
+ public function get_default_available_products() {
+ $this->load_products();
+
+ return $this->products->get_default_available_products();
+ }
+
+ public function get_available_products( $filters = array() ) {
+ $this->load_products();
+
+ return $this->products->get_available_products( $filters );
+ }
+
+ public function get_product_list() {
+ $this->load_products();
+
+ return $this->products;
+ }
+
+ public function is_warenpost_international( $im_product_code ) {
+ $is_wp_int = false;
+
+ if ( $product_data = $this->get_product_data_by_code( $im_product_code ) ) {
+ if ( 1 == $product_data->product_is_wp_int ) {
+ return true;
+ }
+ }
+
+ return $is_wp_int;
+ }
+
+ public function is_warenpost_international_eu( $im_product_code ) {
+ $is_wp_int = false;
+
+ if ( $product_data = $this->get_product_data_by_code( $im_product_code ) ) {
+ if ( 1 == $product_data->product_is_wp_int && 'eu' === $product_data->product_destination ) {
+ return true;
+ }
+ }
+
+ return $is_wp_int;
+ }
+
+ protected function format_dimensions( $product, $type = 'length' ) {
+ $dimension = '';
+
+ if ( ! empty( $product->{"product_{$type}_min"} ) ) {
+ $dimension .= $product->{"product_{$type}_min"};
+
+ if ( ! empty( $product->{"product_{$type}_max"} ) ) {
+ $dimension .= '-' . $product->{"product_{$type}_max"};
+ }
+ } elseif( 0 == $product->{"product_{$type}_min"} ) {
+ $dimension = sprintf( _x( 'until %s', 'dhl', 'woocommerce-germanized' ), $product->{"product_{$type}_max"} );
+ }
+
+ if ( ! empty( $dimension ) ) {
+ $dimension .= ' ' . $product->{"product_{$type}_unit"};
+ }
+
+ return $dimension;
+ }
+
+ public function get_product_data_by_code( $im_product_id ) {
+ $this->load_products();
+
+ return $this->products->get_product_data_by_code( $im_product_id );
+ }
+
+ public function get_product_data( $product_id ) {
+ $this->load_products();
+
+ return $this->products->get_product_data( $product_id );
+ }
+
+ public function get_product_id( $im_product_id ) {
+ $this->load_products();
+ $data = $this->products->get_product_data_by_code( $im_product_id );
+
+ return ( ! empty( $data ) ? $data->product_id : 0 );
+ }
+
+ public function get_product_parent_code( $im_product_id ) {
+ $this->load_products();
+ $data = $this->products->get_product_data_by_code( $im_product_id );
+
+ if ( ! empty( $data ) ) {
+ if ( $data->product_parent_id > 0 ) {
+ $im_product_data = $this->get_product_data( $data->product_parent_id );
+
+ $im_product_id = $im_product_data->product_code;
+ }
+ }
+
+ return $im_product_id;
+ }
+
+ public function product_code_is_parent( $im_product_id ) {
+ $this->load_products();
+ $data = $this->products->get_product_data_by_code( $im_product_id );
+ $is_parent = false;
+
+ if ( ! empty( $data ) ) {
+ if ( $data->product_parent_id > 0 ) {
+ $is_parent = false;
+ } else {
+ $is_parent = true;
+ }
+ }
+
+ return $is_parent;
+ }
+
+ public function get_product_total( $product_code ) {
+ $total = 0;
+
+ if ( $data = $this->get_product_data_by_code( $product_code ) ) {
+ $total = $data->product_price;
+ }
+
+ return $total;
+ }
+
+ public function get_available_products_printable() {
+ $printable = array();
+
+ foreach( $this->get_available_products() as $product ) {
+ $printable[ $product->product_code ] = $this->get_product_preview_data( $product );
+ }
+
+ return $printable;
+ }
+
+ public function get_product_preview_data( $im_product_id ) {
+ $product = is_numeric( $im_product_id ) ? $this->get_product_data_by_code( $im_product_id ) : $im_product_id;
+ $formatted = array(
+ 'title_formatted' => '',
+ 'price_formatted' => '',
+ 'description_formatted' => '',
+ 'information_text_formatted' => '',
+ 'dimensions_formatted' => '',
+ );
+
+ if ( ! $product || ! isset( $product->product_id ) ) {
+ return $formatted;
+ }
+
+ $dimensions = array();
+ $formatted_length = $this->format_dimensions( $product, 'length' );
+ $formatted_width = $this->format_dimensions( $product, 'width' );
+ $formatted_height = $this->format_dimensions( $product, 'height' );
+ $formatted_weight = $this->format_dimensions( $product, 'weight' );
+
+ if ( ! empty( $formatted_length ) ) {
+ $dimensions[] = sprintf( _x( 'Length: %s', 'dhl', 'woocommerce-germanized' ), $formatted_length );
+ }
+
+ if ( ! empty( $formatted_width ) ) {
+ $dimensions[] = sprintf( _x( 'Width: %s', 'dhl', 'woocommerce-germanized' ), $formatted_width );
+ }
+
+ if ( ! empty( $formatted_height ) ) {
+ $dimensions[] = sprintf( _x( 'Height: %s', 'dhl', 'woocommerce-germanized' ), $formatted_height );
+ }
+
+ if ( ! empty( $formatted_weight ) ) {
+ $dimensions[] = sprintf( _x( 'Weight: %s', 'dhl', 'woocommerce-germanized' ), $formatted_weight );
+ }
+
+ $formatted = array_merge( (array) $product, array(
+ 'title_formatted' => wc_gzd_dhl_get_im_product_title( $product->product_name ),
+ 'price_formatted' => wc_price( Package::cents_to_eur( $product->product_price ), array( 'currency' => 'EUR' ) ) . ' ' . _x( 'Total', 'dhl', 'woocommerce-germanized' ) . ' ',
+ 'description_formatted' => ! empty( $product->product_annotation ) ? $product->product_annotation : $product->product_description,
+ 'information_text_formatted' => $product->product_information_text,
+ 'dimensions_formatted' => implode( ' ', $dimensions ),
+ ) );
+
+ return $formatted;
+ }
+
+ public function get_page_formats( $force_refresh = false ) {
+ if ( is_null( $this->page_formats ) ) {
+ $this->page_formats = get_transient( 'wc_gzd_dhl_im_page_formats' );
+
+ if ( ! $this->page_formats || $force_refresh ) {
+ $this->page_formats = array();
+
+ try {
+ $this->page_formats = $this->api->retrievePageFormats();
+
+ set_transient( 'wc_gzd_dhl_im_page_formats', $this->page_formats, DAY_IN_SECONDS );
+ } catch( \Exception $e ) {
+ Package::log( 'Error while refreshing Internetmarke page formats: ' . $e->getMessage() );
+ }
+
+ $page_formats = $this->page_formats;
+ } else {
+ $page_formats = $this->page_formats;
+ }
+ } else {
+ $page_formats = $this->page_formats;
+ }
+
+ return $page_formats;
+ }
+
+ public function get_page_format_list() {
+ $formats = $this->get_page_formats();
+ $options = array();
+
+ foreach( $formats as $format ) {
+ if ( ! $format->isIsAddressPossible() ) {
+ continue;
+ }
+
+ $options[ $format->getId() ] = $format->getName();
+ }
+
+ return $options;
+ }
+
+ public function get_product_services( $im_product_id ) {
+ $this->load_products();
+
+ $product_id = $this->get_product_id( $im_product_id );
+
+ if ( $product_id ) {
+ return $this->products->get_product_services( $product_id );
+ }
+
+ return array();
+ }
+
+ public function get_product_code( $maybe_parent_product_code, $services = array() ) {
+ $this->load_products();
+
+ $product_id = $this->get_product_id( $maybe_parent_product_code );
+
+ if ( $product_id ) {
+ $new_product_data = $this->products->get_product_data_by_services( $product_id, $services );
+
+ if ( $new_product_data ) {
+ return $new_product_data->product_code;
+ } else {
+ return false;
+ }
+ }
+
+ return $maybe_parent_product_code;
+ }
+
+ public function preview_stamp( $product_id, $address_type = 'FrankingZone', $image_id = null ) {
+ $preview_url = false;
+
+ try {
+ if ( $this->is_warenpost_international( $product_id ) ) {
+ if ( $this->is_warenpost_international_eu( $product_id ) ) {
+ $preview_url = trailingslashit( Package::get_assets_url() ) . 'img/wp-int-eu-preview.png';
+ } else {
+ $preview_url = trailingslashit( Package::get_assets_url() ) . 'img/wp-int-preview.png';
+ }
+ } else {
+ $preview_url = $this->api->retrievePreviewVoucherPng( $product_id, $address_type, $image_id );
+ }
+ } catch( \Exception $e ) {}
+
+ return $preview_url;
+ }
+
+ /**
+ * @param DeutschePost $label
+ *
+ * @return mixed
+ */
+ public function get_label( &$label ) {
+ if ( $label->is_warenpost_international() ) {
+ $result = $this->create_or_update_wp_int_label( $label );
+ } else {
+ $result = $this->create_or_update_default_label( $label );
+ }
+
+ $this->invalidate_balance();
+
+ return $result;
+ }
+
+ protected function get_wp_int_api() {
+ if ( is_null( $this->wp_int_api ) ) {
+ $this->wp_int_api = new ImWarenpostIntRest();
+ }
+
+ return $this->wp_int_api;
+ }
+
+ /**
+ * @param DeutschePost $label
+ *
+ * @return mixed
+ */
+ protected function create_or_update_wp_int_label( &$label ) {
+ if ( empty( $label->get_wp_int_awb() ) ) {
+ return $this->get_wp_int_api()->create_label( $label );
+ } else {
+ try {
+ $pdf = $this->get_wp_int_api()->get_pdf( $label->get_wp_int_awb() );
+
+ if ( ! $pdf ) {
+ throw new \Exception( _x( 'Error while fetching label PDF', 'dhl', 'woocommerce-germanized' ) );
+ }
+ } catch( \Exception $e ) {
+ return $this->get_wp_int_api()->create_label( $label );
+ }
+
+ return true;
+ }
+ }
+
+ /**
+ * @param DeutschePost $label
+ *
+ * @return mixed
+ */
+ protected function create_or_update_default_label( &$label ) {
+ if ( empty( $label->get_shop_order_id() ) ) {
+ return $this->create_default_label( $label );
+ } else {
+ if ( ! $this->auth() ) {
+ throw new \Exception( $this->get_authentication_error() );
+ }
+
+ try {
+ $stamp = $this->api->retrieveOrder( $this->get_user()->getUserToken(), $label->get_shop_order_id() );
+ } catch( \Exception $e ) {
+ return $this->create_default_label( $label );
+ }
+
+ return $this->update_default_label( $label, $stamp );
+ }
+ }
+
+ public function get_refund_api() {
+ if ( is_null( $this->refund_api ) ) {
+ $this->refund_api = new ImRefundSoap( $this->partner, array(), Package::get_wsdl_file( Package::get_internetmarke_refund_url() ) );
+ }
+
+ return $this->refund_api;
+ }
+
+ /**
+ * @param DeutschePost $label
+ *
+ * @return false|int
+ */
+ public function refund_label( $label ) {
+ try {
+ if ( $label->is_warenpost_international() ) {
+ return $this->refund_wp_int_label( $label );
+ } else {
+ return $this->refund_default_label( $label );
+ }
+ } catch( \Exception $e ) {
+ throw new \Exception( sprintf( _x( 'Could not refund post label: %s', 'dhl', 'woocommerce-germanized' ), $e->getMessage() ) );
+ }
+ }
+
+ /**
+ * @param DeutschePost $label
+ *
+ * @return false|int
+ * @throws \Exception
+ */
+ protected function refund_default_label( $label ) {
+ $refund = $this->get_refund_api();
+
+ if ( ! $refund ) {
+ throw new \Exception( _x( 'Refund API could not be instantiated', 'dhl', 'woocommerce-germanized' ) );
+ }
+
+ $refund_id = $refund->createRetoureId();
+
+ if ( $refund_id ) {
+ $user = $refund->authenticateUser( Package::get_internetmarke_username(), Package::get_internetmarke_password() );
+
+ if ( $user ) {
+ $transaction_id = $refund->retoureVouchers( $user->getUserToken(), $refund_id, $label->get_shop_order_id() );
+ }
+
+ Package::log( sprintf( 'Refunded DP label %s: %s', $label->get_number(), $transaction_id ) );
+
+ return $transaction_id;
+ }
+ }
+
+ /**
+ * @param DeutschePost $label
+ *
+ * @return false|int
+ * @throws \Exception
+ */
+ protected function refund_wp_int_label( $label ) {
+ return false;
+ }
+
+ /**
+ * @param DeutschePost $label
+ *
+ * @return mixed
+ */
+ public function delete_label( &$label ) {
+ if ( ! empty( $label->get_shop_order_id() ) ) {
+ $transaction_id = $this->refund_label( $label );
+
+ if ( false !== $transaction_id ) {
+ $this->invalidate_balance();
+ }
+
+ /**
+ * Action fires before deleting a Deutsche Post PDF label through an API call.
+ *
+ * @param DeutschePost $label The label object.
+ *
+ * @since 3.2.0
+ * @package Vendidero/Germanized/DHL
+ */
+ do_action( 'woocommerce_gzd_dhl_deutsche_post_label_api_before_delete', $label );
+
+ $label->set_number( '' );
+ $label->set_wp_int_awb( '' );
+ $label->set_wp_int_barcode( '' );
+ $label->set_shop_order_id( '' );
+
+ /**
+ * Action fires after deleting a Deutsche Post PDF label through an API call.
+ *
+ * @param DeutschePost $label The label object.
+ *
+ * @since 3.2.0
+ * @package Vendidero/Germanized/DHL
+ */
+ do_action( 'woocommerce_gzd_dhl_deutsche_post_label_api_deleted', $label );
+
+ return $label;
+ }
+
+ return false;
+ }
+
+ protected function get_shipment_address_prop( $shipment, $prop, $address_type = '' ) {
+ $getter = "get_{$prop}";
+
+ if ( ! empty( $address_type ) ) {
+ $getter = "get_{$address_type}_{$prop}";
+ }
+
+ if ( is_callable( array( $shipment, $getter ) ) ) {
+ return $shipment->$getter();
+ } else {
+ return '';
+ }
+ }
+
+ protected function get_shipment_address_data( $shipment, $address_type = '' ) {
+ $person_name = new PersonName( '', '', $this->get_shipment_address_prop( $shipment, 'first_name', $address_type ), $this->get_shipment_address_prop( $shipment, 'last_name', $address_type ) );
+
+ if ( $this->get_shipment_address_prop( $shipment, 'company', $address_type ) ) {
+ $name = new Name( null, new CompanyName( $this->get_shipment_address_prop( $shipment, 'company', $address_type ), $receiver_person_name ) );
+ } else {
+ $name = new Name( $person_name, null );
+ }
+
+ $additional = $this->get_shipment_address_prop( $shipment, 'address_2', $address_type );
+
+ if ( 'simple' === $shipment->get_type() && $shipment->send_to_external_pickup( 'packstation' ) ) {
+ $additional = ParcelLocator::get_postnumber_by_shipment( $shipment );
+ }
+
+ $address = new Address(
+ $additional,
+ $this->get_shipment_address_prop( $shipment, 'address_street', $address_type ),
+ $this->get_shipment_address_prop( $shipment, 'address_street_number', $address_type ),
+ $this->get_shipment_address_prop( $shipment, 'postcode', $address_type ),
+ $this->get_shipment_address_prop( $shipment, 'city', $address_type ),
+ Package::get_country_iso_alpha3( $this->get_shipment_address_prop( $shipment, 'country', $address_type ) )
+ );
+
+ $named_address = new \baltpeter\Internetmarke\NamedAddress( $name, $address );
+
+ return $named_address;
+ }
+
+ protected function get_setting_address_data() {
+ $person_name = new PersonName( '', '', Package::get_setting( 'shipper_first_name' ), Package::get_setting( 'shipper_last_name' ) );
+ $sender_country = Package::get_country_iso_alpha3( Package::get_setting( 'shipper_country' ) );
+
+ if ( Package::get_setting( 'shipper_company' ) ) {
+ $name = new Name( null, new CompanyName( Package::get_setting( 'shipper_company' ), $person_name ) );
+ } else {
+ $name = new Name( $person_name, null );
+ }
+
+ $address = new Address( '', Package::get_setting( 'shipper_street' ), Package::get_setting( 'shipper_street_number' ), Package::get_setting( 'shipper_postcode' ), Package::get_setting( 'shipper_city' ), $sender_country );
+ $sender = new \baltpeter\Internetmarke\NamedAddress( $name, $address );
+
+ return $sender;
+ }
+
+ /**
+ * @param DeutschePost|DeutschePostReturn $label
+ */
+ protected function create_default_label( &$label ) {
+ $shipment = $label->get_shipment();
+
+ if ( ! $shipment ) {
+ throw new \Exception( sprintf( _x( 'Could not fetch shipment %d.', 'dhl', 'woocommerce-germanized' ), $label->get_shipment_id() ) );
+ }
+
+ if ( 'return' === $label->get_type() ) {
+ $sender = $this->get_shipment_address_data( $shipment, 'sender' );
+ $receiver = $this->get_setting_address_data();
+
+ $address_binding = new \baltpeter\Internetmarke\AddressBinding( $sender, $receiver );
+ } else {
+ $sender = $this->get_setting_address_data();
+ $receiver = $this->get_shipment_address_data( $shipment );
+
+ $address_binding = new \baltpeter\Internetmarke\AddressBinding( $sender, $receiver );
+ }
+
+ if ( ! $this->auth() ) {
+ throw new \Exception( $this->get_authentication_error() );
+ }
+
+ try {
+ $shop_order_id = $this->api->createShopOrderId( $this->get_user()->getUserToken() );
+
+ if ( ! $shop_order_id ) {
+ throw new \Exception( _x( 'Error while generating shop order id.', 'dhl', 'woocommerce-germanized' ) );
+ }
+
+ $label->set_shop_order_id( $shop_order_id );
+
+ $position = new \baltpeter\Internetmarke\Position(
+ /**
+ * Adjust the Deutsche Post (Internetmarke) label print X position.
+ *
+ * @param mixed $x The x axis position.
+ * @param DeutschePost $label The label instance.
+ * @param Shipment $shipment The shipment instance.
+ *
+ * @since 3.4.5
+ * @package Vendidero/Germanized/DHL
+ */
+ apply_filters( 'woocommerce_gzd_deutsche_post_label_api_position_x', Package::get_setting( 'deutsche_post_label_position_x' ), $label, $shipment ),
+ /**
+ * Adjust the Deutsche Post (Internetmarke) label print Y position.
+ *
+ * @param mixed $y The y axis position.
+ * @param DeutschePost $label The label instance.
+ * @param Shipment $shipment The shipment instance.
+ *
+ * @since 3.4.5
+ * @package Vendidero/Germanized/DHL
+ */
+ apply_filters( 'woocommerce_gzd_deutsche_post_label_api_position_y', Package::get_setting( 'deutsche_post_label_position_y' ), $label, $shipment ),
+ apply_filters( 'woocommerce_gzd_deutsche_post_label_api_page_number', 1, $label, $shipment )
+ );
+
+ $order_item = new \baltpeter\Internetmarke\OrderItem( $label->get_product_id(), null, $address_binding, $position, 'AddressZone' );
+ $stamp = $this->api->checkoutShoppingCartPdf( $this->get_user()->getUserToken(), $label->get_page_format(), array( $order_item ), $label->get_stamp_total(), $shop_order_id, null, true, 2 );
+
+ return $this->update_default_label( $label, $stamp );
+ } catch( \Exception $e ) {
+ throw new \Exception( sprintf( _x( 'Error while trying to purchase the stamp. Please manually refresh your product database and try again.', 'dhl', 'woocommerce-germanized' ), Package::get_deutsche_post_shipping_provider()->get_edit_link( 'label' ) ) );
+ }
+ }
+
+ /**
+ * @param DeutschePost $label
+ * @param \stdClass $stamp
+ *
+ * @return mixed
+ * @throws \Exception
+ */
+ protected function update_default_label( &$label, $stamp ) {
+ if ( isset( $stamp->link ) ) {
+
+ $label->set_original_url( $stamp->link );
+ $voucher_list = $stamp->shoppingCart->voucherList;
+
+ if ( ! empty( $voucher_list->voucher ) ) {
+ foreach ( $voucher_list->voucher as $i => $voucher ) {
+
+ if ( isset( $voucher->trackId ) ) {
+ $label->set_number( $voucher->trackId );
+ } else {
+ $label->set_number( $voucher->voucherId );
+ }
+
+ $label->set_voucher_id( $voucher->voucherId );
+ }
+ }
+
+ if ( isset( $stamp->manifestLink ) ) {
+ $label->set_manifest_url( $stamp->manifestLink );
+ }
+
+ $label->save();
+ $result = $label->download_label_file( $stamp->link );
+
+ if ( ! $result ) {
+ throw new \Exception( _x( 'Error while downloading the PDF stamp.', 'dhl', 'woocommerce-germanized' ) );
+ }
+
+ $label->save();
+
+ return $label;
+ } else {
+ throw new \Exception( _x( 'Invalid stamp response.', 'dhl', 'woocommerce-germanized' ) );
+ }
+ }
+
+ public function update_products() {
+ $this->load_products();
+
+ return $this->products->update();
+ }
+}
diff --git a/packages/woocommerce-germanized-dhl/src/Api/LabelSoap.php b/packages/woocommerce-germanized-dhl/src/Api/LabelSoap.php
new file mode 100644
index 000000000..ebeab3ea1
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/Api/LabelSoap.php
@@ -0,0 +1,675 @@
+get_auth_api()->get_access_token( Package::get_gk_api_user(), Package::get_gk_api_signature() );
+ }
+
+ public function test_connection() {
+
+ }
+
+ /**
+ * @param Label\DHL $label
+ *
+ * @return mixed
+ * @throws Exception
+ */
+ public function get_label( &$label ) {
+ if ( empty( $label->get_number() ) ) {
+ return $this->create_label( $label );
+ } else {
+ $soap_request = array(
+ 'Version' => array(
+ 'majorRelease' => '3',
+ 'minorRelease' => '1'
+ ),
+ 'shipmentNumber' => $label->get_number(),
+ 'labelResponseType' => 'B64',
+ );
+
+ try {
+ $soap_client = $this->get_access_token();
+ Package::log( '"getLabel" called with: ' . print_r( $soap_request, true ) );
+
+ $response_body = $soap_client->getLabel( $soap_request );
+ Package::log( 'Response: Successful' );
+
+ } catch ( Exception $e ) {
+ Package::log( 'Response Error: ' . $e->getMessage() );
+ throw $e;
+ }
+
+ // Label not found
+ if ( 2000 === $response_body->Status->statusCode ) {
+ return $this->create_label( $label );
+ } else {
+ return $this->update_label( $label, $response_body->Status, $response_body );
+ }
+ }
+ }
+
+ /**
+ * @param Label\DHL $label
+ *
+ * @return mixed
+ *
+ * @throws Exception
+ */
+ public function create_label( &$label ) {
+ try {
+ $soap_request = $this->get_create_label_request( $label );
+ $soap_client = $this->get_access_token();
+ Package::log( '"createShipmentOrder" called with: ' . print_r( $soap_request, true ) );
+
+ $response_body = $soap_client->createShipmentOrder( $soap_request );
+ Package::log( 'Response: Successful' );
+
+ } catch ( Exception $e ) {
+ Package::log( 'Response Error: ' . $e->getMessage() );
+
+ switch( $e->getMessage() ) {
+ case "Unauthorized":
+ throw new Exception( _x( 'Your DHL API credentials seem to be invalid. Please check your DHL settings.', 'dhl', 'woocommerce-germanized' ) );
+ break;
+ case "SOAP-ERROR: Encoding: object has no 'customsTariffNumber' property":
+ case "SOAP-ERROR: Encoding: object has no 'countryCodeOrigin' property":
+ throw new Exception( _x( 'Your products are missing data relevant for custom declarations. Please provide missing DHL fields (country of origin, HS code) in your product data > shipping tab.', 'dhl', 'woocommerce-germanized' ) );
+ break;
+ }
+
+ throw $e;
+ }
+
+ if ( ! isset( $response_body->Status ) || ! isset( $response_body->CreationState ) ) {
+
+ if ( isset( $response_body->Status ) && ! empty( $response_body->Status->statusText ) ) {
+ throw new Exception( sprintf( _x( 'There was an error contacting the DHL API: %s.', 'dhl', 'woocommerce-germanized' ), $response_body->Status->statusText ) );
+ }
+
+ throw new Exception( _x( 'An error ocurred while contacting the DHL API. Please consider enabling the sandbox mode.', 'dhl', 'woocommerce-germanized' ) );
+ }
+
+ return $this->update_label( $label, $response_body->Status, $response_body->CreationState );
+ }
+
+ /**
+ * @param Label\DHL $label
+ * @param $status
+ * @param $response_body
+ *
+ * @return mixed
+ * @throws Exception
+ */
+ protected function update_label( &$label, $status, $response_body ) {
+ if ( 0 !== $status->statusCode ) {
+ if ( isset( $response_body->LabelData->Status ) && isset( $response_body->LabelData->Status->statusMessage ) ) {
+ $messages = (array) $response_body->LabelData->Status->statusMessage;
+ $messages = implode( "\n", array_unique( $messages ) );
+
+ throw new Exception( $messages );
+ } else {
+ throw new Exception( _x( 'There was an error generating the label. Please try again or consider switching to sandbox mode.', 'dhl', 'woocommerce-germanized' ) );
+ }
+ } else {
+ $return_label = false;
+
+ try {
+
+ if ( isset( $response_body->shipmentNumber ) ) {
+ $label->set_number( $response_body->shipmentNumber );
+ }
+
+ // Make sure the label does exist from this point on so that the parent id is available for returns.
+ $label->save();
+
+ // Create separate return label
+ if ( isset( $response_body->returnShipmentNumber ) ) {
+ $return_label = $label->get_inlay_return_label();
+
+ if ( ! $return_label ) {
+ if ( $return_label = Factory::get_label( 0, $label->get_shipping_provider(), 'inlay_return' ) ) {
+ $return_label->set_parent_id( $label->get_id() );
+ $return_label->set_shipment_id( $label->get_shipment_id() );
+ $return_label->set_shipping_provider( $label->get_shipping_provider() );
+
+ if ( $shipment = $label->get_shipment() ) {
+ $return_label->set_sender_address( $shipment->get_address() );
+ }
+ }
+ }
+
+ if ( $return_label ) {
+ $return_label->set_number( $response_body->returnShipmentNumber );
+ }
+ }
+
+ $default_file = base64_decode( $response_body->LabelData->labelData );
+ $return_file = false;
+
+ // Try to split the PDF to extract return label
+ if ( $return_label ) {
+ $splitter = $splitter = new PDFSplitter( $default_file, true );
+ $pdfs = $splitter->split();
+
+ if ( $pdfs && ! empty( $pdfs ) && sizeof( $pdfs ) > 1 ) {
+ $return_file = $pdfs[1];
+ }
+
+ if ( $return_file ) {
+ $return_label->upload_label_file( $return_file );
+ }
+
+ $return_label->save();
+ }
+
+ // Store the downloaded label as default file
+ $path = $label->upload_label_file( $default_file, 'default' );
+
+ // Merge export label into label path so that by default the shop owner downloads the merged file
+ if ( isset( $response_body->LabelData->exportLabelData ) ) {
+
+ // Save export file
+ $label->upload_label_file( base64_decode( $response_body->LabelData->exportLabelData ), 'export' );
+
+ // Merge files
+ $merger = new PDFMerger();
+ $merger->add( $label->get_default_file() );
+ $merger->add( $label->get_export_file() );
+
+ $filename_label = $label->get_filename();
+ $file = $merger->output( $filename_label, 'S' );
+
+ $label->upload_label_file( $file );
+ } else {
+ $label->set_path( $path );
+ }
+
+ } catch( Exception $e ) {
+ // Delete the label dues to errors.
+ $label->delete();
+
+ throw new Exception( _x( 'Error while creating and uploading the label', 'dhl', 'woocommerce-germanized' ) );
+ }
+
+ return $label;
+ }
+ }
+
+ /**
+ * @param Label\DHL $label
+ *
+ * @throws Exception
+ */
+ protected function delete_label_call( &$label ) {
+ $soap_request = array(
+ 'Version' => array(
+ 'majorRelease' => '3',
+ 'minorRelease' => '1'
+ ),
+ 'shipmentNumber' => $label->get_number()
+ );
+
+ try {
+ Package::log( '"deleteShipmentOrder" called with: ' . print_r( $soap_request, true ) );
+
+ $soap_client = $this->get_access_token();
+ $response_body = $soap_client->deleteShipmentOrder( $soap_request );
+
+ Package::log( 'Response Body: ' . print_r( $response_body, true ) );
+
+ } catch ( Exception $e ) {
+ throw $e;
+ }
+
+ /**
+ * Action fires after deleting a DHL PDF label through an API call.
+ *
+ * @param Label\DHL $label The label object.
+ *
+ * @since 3.0.0
+ * @package Vendidero/Germanized/DHL
+ */
+ do_action( 'woocommerce_gzd_dhl_label_api_deleted', $label );
+
+ if ( 0 !== $response_body->Status->statusCode ) {
+ throw new Exception( sprintf( _x( 'Could not delete label - %s', 'dhl', 'woocommerce-germanized' ), $response_body->Status->statusMessage ) );
+ }
+
+ return $label;
+ }
+
+ /**
+ * @param Label\DHL $label
+ *
+ * @throws Exception
+ */
+ public function delete_label( &$label ) {
+ try {
+ if ( ! empty( $label->get_number() ) ) {
+ return $this->delete_label_call( $label );
+ }
+ } catch ( Exception $e ) {
+ throw $e;
+ }
+
+ return false;
+ }
+
+ protected function get_account_number( $dhl_product ) {
+ $product_number = preg_match('!\d+!', $dhl_product, $matches );
+
+ if ( $product_number ) {
+ $account_number = Package::get_setting( 'account_number' ) . $matches[0] . Package::get_participation_number( $dhl_product );
+
+ return $account_number;
+ } else {
+ throw new Exception( _x( 'Could not create account number - no product number.', 'dhl', 'woocommerce-germanized' ) );
+ }
+ }
+
+ protected function get_return_account_number() {
+ $product_number = self::DHL_RETURN_PRODUCT;
+ $account_number = Package::get_setting( 'account_number' ) . $product_number . Package::get_participation_number( 'return' );
+
+ return $account_number;
+ }
+
+ /**
+ * @param Label\DHL $label
+ * @return array
+ *
+ * @throws Exception
+ */
+ protected function get_create_label_request( $label ) {
+ $shipment = $label->get_shipment();
+
+ if ( ! $shipment ) {
+ throw new Exception( sprintf( _x( 'Could not fetch shipment %d.', 'dhl', 'woocommerce-germanized' ), $label->get_shipment_id() ) );
+ }
+
+ $services = array();
+ $bank_data = array();
+
+ foreach( $label->get_services() as $service ) {
+
+ $services[ $service ] = array(
+ 'active' => 1
+ );
+
+ switch ( $service ) {
+ case 'AdditionalInsurance':
+ $services[ $service ]['insuranceAmount'] = $shipment->get_total();
+ break;
+ case 'IdentCheck':
+ $services[ $service ]['Ident']['surname'] = $shipment->get_last_name();
+ $services[ $service ]['Ident']['givenName'] = $shipment->get_first_name();
+ $services[ $service ]['Ident']['dateOfBirth'] = $label->get_ident_date_of_birth() ? $label->get_ident_date_of_birth()->date( 'Y-m-d' ) : '';
+ $services[ $service ]['Ident']['minimumAge'] = $label->get_ident_min_age();
+ break;
+ case 'CashOnDelivery':
+ $services[ $service ]['codAmount'] = $label->get_cod_total();
+
+ $bank_data_map = array(
+ 'bank_holder' => 'accountOwner',
+ 'bank_name' => 'bankName',
+ 'bank_iban' => 'iban',
+ 'bank_ref' => 'note1',
+ 'bank_ref_2' => 'note2',
+ 'bank_bic' => 'bic'
+ );
+
+ $ref_replacements = wc_gzd_dhl_get_label_payment_ref_placeholder( $shipment );
+
+ foreach ( $bank_data_map as $key => $value ) {
+ if ( $setting_value = Package::get_setting( $key ) ) {
+ $bank_data[ $value ] = $setting_value;
+
+ if ( in_array( $key, array( 'bank_ref', 'bank_ref_2' ) ) ) {
+ $bank_data[ $value ] = str_replace( array_keys( $ref_replacements ), array_values( $ref_replacements ), $bank_data[ $value ] );
+ }
+ }
+ }
+ break;
+ case 'PreferredDay':
+ $services[ $service ]['details'] = $label->get_preferred_day() ? $label->get_preferred_day()->date( 'Y-m-d' ) : '';
+ break;
+ case 'VisualCheckOfAge':
+ $services[ $service ]['type'] = $label->get_visual_min_age();
+ break;
+ case 'PreferredLocation':
+ $services[ $service ]['details'] = $label->get_preferred_location();
+ break;
+ case 'PreferredNeighbour':
+ $services[ $service ]['details'] = $label->get_preferred_neighbor();
+ break;
+ case 'ParcelOutletRouting':
+ if ( ! empty( $shipment->get_email() ) ) {
+ $services[ $service ]['details'] = $shipment->get_email();
+ }
+ break;
+ }
+ }
+
+ $dhl_label_body = array(
+ 'Version' => array(
+ 'majorRelease' => '3',
+ 'minorRelease' => '1'
+ ),
+ 'labelResponseType' => 'B64',
+ 'ShipmentOrder' => array (
+ 'sequenceNumber' => $label->get_shipment_id(),
+ 'Shipment' => array(
+ 'ShipmentDetails' => array(
+ 'product' => $label->get_product_id(),
+ 'accountNumber' => self::get_account_number( $label->get_product_id() ),
+ 'customerReference' => wc_gzd_dhl_get_label_customer_reference( $label, $shipment ),
+ 'shipmentDate' => Package::get_date_de_timezone( 'Y-m-d' ),
+ 'ShipmentItem' => array(
+ 'weightInKG' => $label->get_weight(),
+ 'lengthInCM' => $label->has_dimensions() ? $label->get_length() : '',
+ 'widthInCM' => $label->has_dimensions() ? $label->get_width() : '',
+ 'heightInCM' => $label->has_dimensions() ? $label->get_height() : '',
+ ),
+ 'Service' => $services,
+ 'Notification' => ( apply_filters( 'woocommerce_gzd_dhl_label_api_enable_notification', $label->has_email_notification(), $label ) && ! empty( $shipment->get_email() ) ) ? array( 'recipientEmailAddress' => $shipment->get_email() ) : array(),
+ 'BankData' => $bank_data,
+ ),
+ 'Receiver' => array(
+ 'name1' => $shipment->get_company() ? $shipment->get_company() : $shipment->get_formatted_full_name(),
+ 'Address' => array(
+ 'name2' => $shipment->get_company() ? $shipment->get_formatted_full_name() : '',
+ /**
+ * By default the name3 parameter is used to transmit the additional
+ * address field to the DHL API. You may adjust the field value by using this filter.
+ *
+ * @param string $value The field value.
+ * @param Label\DHL $label The label instance.
+ *
+ * @since 3.0.3
+ * @package Vendidero/Germanized/DHL
+ */
+ 'name3' => apply_filters( 'woocommerce_gzd_dhl_label_api_receiver_name3', wc_gzd_dhl_get_label_shipment_address_addition( $shipment ), $label ),
+ 'streetName' => $shipment->get_address_street(),
+ 'streetNumber' => wc_gzd_dhl_get_label_shipment_street_number( $shipment ),
+ 'zip' => $shipment->get_postcode(),
+ 'city' => $shipment->get_city(),
+ 'Origin' => array(
+ 'countryISOCode' => $shipment->get_country(),
+ 'state' => wc_gzd_dhl_format_label_state( $shipment->get_state(), $shipment->get_country() )
+ )
+ ),
+ 'Communication' => array(
+ /**
+ * Choose whether to transmit the full name of the shipment receiver as contactPerson
+ * while creating a label.
+ *
+ * @param string $name The name of the shipmen receiver.
+ * @param Label\DHL $label The label instance.
+ *
+ * @since 3.0.5
+ * @package Vendidero/Germanized/DHL
+ */
+ 'contactPerson' => apply_filters( 'woocommerce_gzd_dhl_label_api_communication_contact_person', $shipment->get_formatted_full_name(), $label ),
+ /**
+ * Choose whether to transfer the phone number to DHL on creating a label.
+ * By default the phone number is not transmitted.
+ *
+ * @param string $phone The phone number.
+ * @param Label\DHL $label The label instance.
+ *
+ * @since 3.0.3
+ * @package Vendidero/Germanized/DHL
+ */
+ 'phone' => apply_filters( 'woocommerce_gzd_dhl_label_api_communication_phone', '', $label ),
+ /**
+ * Choose whether to transfer the email to DHL on creating a label.
+ * By default the email is only transmitted if the customer opted in.
+ *
+ * This email address is not used to notify the customer via DHL. It is only
+ * meant for communicaton purposes.
+ *
+ * @param string $email The email.
+ * @param Label\DHL $label The label instance.
+ *
+ * @since 3.0.3
+ * @package Vendidero/Germanized/DHL
+ */
+ 'email' => apply_filters( 'woocommerce_gzd_dhl_label_api_communication_email', $label->has_email_notification() ? $shipment->get_email() : '', $label ),
+ )
+ )
+ )
+ )
+ );
+
+ /**
+ * This filter allows using a ShipperReference configured in the GKP instead of transmitting
+ * the shipper data from the DHL settings. Use this filter carefully and make sure that the
+ * reference exists.
+ *
+ * @param string $shipper_reference The shipper reference from the GKP.
+ * @param Label\DHL $label The label instance.
+ *
+ * @since 3.0.5
+ * @package Vendidero/Germanized/DHL
+ */
+ $shipper_reference = apply_filters( 'woocommerce_gzd_dhl_label_api_shipper_reference', '', $label );
+
+ if ( ! empty( $shipper_reference ) ) {
+ $dhl_label_body['ShipmentOrder']['Shipment']['ShipperReference'] = $shipper_reference;
+ } else {
+ $name1 = apply_filters( 'woocommerce_gzd_dhl_label_api_shipper_name1', Package::get_setting( 'shipper_company' ) ? Package::get_setting( 'shipper_company' ) : Package::get_setting( 'shipper_name' ), $label );
+ $name2 = apply_filters( 'woocommerce_gzd_dhl_label_api_shipper_name2', Package::get_setting( 'shipper_company' ) ? Package::get_setting( 'shipper_name' ) : '', $label );
+
+ $dhl_label_body['ShipmentOrder']['Shipment']['Shipper'] = array(
+ 'Name' => array(
+ 'name1' => $name1,
+ 'name2' => $name2,
+ ),
+ 'Address' => array(
+ 'streetName' => apply_filters( 'woocommerce_gzd_dhl_label_api_shipper_street_name', Package::get_setting( 'shipper_street' ), $label ),
+ 'streetNumber' => apply_filters( 'woocommerce_gzd_dhl_label_api_shipper_street_number', Package::get_setting( 'shipper_street_number' ), $label ),
+ 'zip' => apply_filters( 'woocommerce_gzd_dhl_label_api_shipper_zip', Package::get_setting( 'shipper_postcode' ), $label ),
+ 'city' => apply_filters( 'woocommerce_gzd_dhl_label_api_shipper_city', Package::get_setting( 'shipper_city' ), $label ),
+ 'Origin' => array(
+ 'countryISOCode' => apply_filters( 'woocommerce_gzd_dhl_label_api_shipper_country', Package::get_setting( 'shipper_country' ), $label ),
+ 'state' => apply_filters( 'woocommerce_gzd_dhl_label_api_shipper_state', wc_gzd_dhl_format_label_state( Package::get_setting( 'shipper_state' ), Package::get_setting( 'shipper_country' ) ), $label ),
+ )
+ ),
+ 'Communication' => array(
+ 'phone' => apply_filters( 'woocommerce_gzd_dhl_label_api_shipper_phone', Package::get_setting( 'contact_phone' ), $label ),
+ 'email' => apply_filters( 'woocommerce_gzd_dhl_label_api_shipper_email', Package::get_setting( 'contact_email' ), $label ),
+ 'contactPerson' => apply_filters( 'woocommerce_gzd_dhl_label_api_shipper_contact_person', Package::get_setting( 'shipper_name' ), $label ),
+ )
+ );
+ }
+
+ $label_custom_format = wc_gzd_dhl_get_custom_label_format( $label );
+ $label_custom_return_format = wc_gzd_dhl_get_custom_label_format( $label, 'inlay_return' );
+
+ if ( ! empty( $label_custom_format ) ) {
+ $dhl_label_body['labelFormat'] = $label_custom_format;
+ }
+
+ if ( ! empty( $label_custom_return_format ) ) {
+ $dhl_label_body['labelFormatRetoure'] = $label_custom_return_format;
+ }
+
+ if ( $shipment->send_to_external_pickup( array_keys( wc_gzd_dhl_get_pickup_types() ) ) ) {
+ // Address is NOT needed if using a parcel shop
+ unset( $dhl_label_body['ShipmentOrder']['Shipment']['Receiver']['Address'] );
+
+ $parcel_shop = array(
+ 'zip' => $shipment->get_postcode(),
+ 'city' => $shipment->get_city(),
+ 'Origin' => array(
+ 'countryISOCode' => $shipment->get_country(),
+ 'state' => wc_gzd_dhl_format_label_state( $shipment->get_state(), $shipment->get_country() )
+ )
+ );
+
+ $address_number = filter_var( $shipment->get_address_1(), FILTER_SANITIZE_NUMBER_INT );
+
+ if ( $shipment->send_to_external_pickup( 'packstation' ) ) {
+ $parcel_shop['postNumber'] = ParcelLocator::get_postnumber_by_shipment( $shipment );
+ $parcel_shop['packstationNumber'] = $address_number;
+
+ $dhl_label_body['ShipmentOrder']['Shipment']['Receiver']['Packstation'] = $parcel_shop;
+ }
+
+ if ( $shipment->send_to_external_pickup( 'postoffice' ) || $shipment->send_to_external_pickup( 'parcelshop' ) ) {
+ if ( $post_number = ParcelLocator::get_postnumber_by_shipment( $shipment ) ) {
+ $parcel_shop['postNumber'] = $post_number;
+ unset( $dhl_label_body['ShipmentOrder']['Shipment']['Receiver']['Communication']['email'] );
+ }
+
+ $parcel_shop['postfilialNumber'] = $address_number;
+ $dhl_label_body['ShipmentOrder']['Shipment']['Receiver']['Postfiliale'] = $parcel_shop;
+ }
+ }
+
+ if ( $label->has_inlay_return() ) {
+ $dhl_label_body['ShipmentOrder']['Shipment']['ShipmentDetails']['returnShipmentAccountNumber'] = self::get_return_account_number();
+ $dhl_label_body['ShipmentOrder']['Shipment']['ShipmentDetails']['returnShipmentReference'] = wc_gzd_dhl_get_inlay_return_label_reference( $label, $shipment );
+
+ $dhl_label_body['ShipmentOrder']['Shipment']['ReturnReceiver'] = array(
+ 'Name' => array(
+ 'name1' => $label->get_return_company() ? $label->get_return_company() : $label->get_return_formatted_full_name(),
+ 'name2' => $label->get_return_company() ? $label->get_return_formatted_full_name() : ''
+ ),
+ 'Address' => array(
+ 'streetName' => $label->get_return_street(),
+ 'streetNumber' => $label->get_return_street_number(),
+ 'zip' => $label->get_return_postcode(),
+ 'city' => $label->get_return_city(),
+ 'Origin' => array(
+ 'countryISOCode' => $label->get_return_country(),
+ 'state' => wc_gzd_dhl_format_label_state( $label->get_return_state(), $label->get_return_country() ),
+ )
+ ),
+ 'Communication' => array(
+ 'contactPerson' => $label->get_return_formatted_full_name(),
+ 'phone' => $label->get_return_phone(),
+ 'email' => $label->get_return_email()
+ )
+ );
+ }
+
+ if ( $label->codeable_address_only() ) {
+ $dhl_label_body['ShipmentOrder']['PrintOnlyIfCodeable'] = array( 'active' => 1 );
+ }
+
+ if ( Package::is_crossborder_shipment( $shipment->get_country() ) ) {
+
+ if ( sizeof( $shipment->get_items() ) > self::DHL_MAX_ITEMS ) {
+ throw new Exception( sprintf( _x( 'Only %s shipment items can be processed, your shipment has %s items.', 'dhl', 'woocommerce-germanized' ), self::DHL_MAX_ITEMS, sizeof( $shipment->get_items() ) ) );
+ }
+
+ $customs_label_data = wc_gzd_dhl_get_shipment_customs_data( $label );
+ $customs_items = array();
+
+ foreach( $customs_label_data['items'] as $item_id => $item_data ) {
+ $customs_items[] = array(
+ 'description' => $item_data['description'],
+ 'countryCodeOrigin' => $item_data['origin_code'],
+ 'customsTariffNumber' => $item_data['tariff_number'],
+ 'amount' => $item_data['quantity'],
+ /**
+ * netWeightInKG is defined as the weight per item (e.g. 2 items in case the quantity equals 2).
+ */
+ 'netWeightInKG' => $item_data['single_weight_in_kg'],
+ /**
+ * Single product value per item
+ */
+ 'customsValue' => $item_data['single_value']
+ );
+ }
+
+ $customs_data = array(
+ 'termsOfTrade' => $label->get_duties(),
+ 'additionalFee' => $customs_label_data['additional_fee'],
+ 'exportTypeDescription' => $customs_label_data['export_type_description'],
+ 'placeOfCommital' => $customs_label_data['place_of_commital'],
+ 'ExportDocPosition' => $customs_items,
+ /**
+ * Filter to allow adjusting the export type of a DHL label (for customs). Could be:
+ *
+ * OTHER
+ * PRESENT
+ * COMMERCIAL_SAMPLE
+ * DOCUMENT
+ * RETURN_OF_GOODS
+ * COMMERCIAL_GOODS
+ *
+ *
+ * @param string $export_type The export type.
+ * @param Label\Label $label The label instance.
+ *
+ * @since 3.3.0
+ * @package Vendidero/Germanized/DHL
+ */
+ 'exportType' => strtoupper( apply_filters( 'woocommerce_gzd_dhl_label_api_export_type', 'COMMERCIAL_GOODS', $label ) ),
+ /**
+ * Filter to allow adjusting the export invoice number.
+ *
+ * @param string $invoice_number The invoice number.
+ * @param Label\Label $label The label instance.
+ *
+ * @since 3.3.4
+ * @package Vendidero/Germanized/DHL
+ */
+ 'invoiceNumber' => apply_filters( 'woocommerce_gzd_dhl_label_api_export_invoice_number', $customs_label_data['invoice_number'], $label )
+ );
+
+ $dhl_label_body['ShipmentOrder']['Shipment']['ExportDocument'] = $customs_data;
+ }
+
+ // Unset/remove any items that are empty strings or 0, even if required!
+ $this->body_request = $this->walk_recursive_remove( $dhl_label_body );
+
+ // Ensure Export Document is set before adding additional fee
+ if ( isset( $this->body_request['ShipmentOrder']['Shipment']['ExportDocument'] ) && ! isset( $this->body_request['ShipmentOrder']['Shipment']['ExportDocument']['additionalFee'] ) ) {
+ // Additional fees, required and 0 so place after check
+ $this->body_request['ShipmentOrder']['Shipment']['ExportDocument']['additionalFee'] = 0;
+ }
+
+ // If "Ident-Check" enabled, then ensure both fields are passed even if empty
+ if ( $label->has_service( 'IdentCheck' ) ) {
+ if ( ! isset( $this->body_request['ShipmentOrder']['Shipment']['ShipmentDetails']['Service']['IdentCheck']['Ident']['minimumAge'] ) ) {
+ $this->body_request['ShipmentOrder']['Shipment']['ShipmentDetails']['Service']['IdentCheck']['Ident']['minimumAge'] = '';
+ }
+ if ( ! isset( $this->body_request['ShipmentOrder']['Shipment']['ShipmentDetails']['Service']['IdentCheck']['Ident']['dateOfBirth'] ) ) {
+ $this->body_request['ShipmentOrder']['Shipment']['ShipmentDetails']['Service']['IdentCheck']['Ident']['dateOfBirth'] = '';
+ }
+ }
+
+ return $this->body_request;
+ }
+}
diff --git a/packages/woocommerce-germanized-dhl/src/Api/Paket.php b/packages/woocommerce-germanized-dhl/src/Api/Paket.php
new file mode 100644
index 000000000..e6d13c097
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/Api/Paket.php
@@ -0,0 +1,279 @@
+country_code = $country_code;
+ }
+
+ public function get_label_api() {
+ $error_message = '';
+
+ if ( is_null( $this->label_api ) ) {
+ try {
+ $this->label_api = new LabelSoap();
+ } catch( Exception $e ) {
+ $error_message = $e->getMessage();
+
+ $this->label_api = null;
+ }
+ }
+
+ if ( is_null( $this->label_api ) ) {
+ if ( ! empty( $error_message ) ) {
+ throw new Exception( sprintf( _x( 'Label API not available: %s', 'dhl', 'woocommerce-germanized' ), $error_message ) );
+ } else {
+ throw new Exception( _x( 'Label API not available', 'dhl', 'woocommerce-germanized' ) );
+ }
+ }
+
+ return $this->label_api;
+ }
+
+ public function get_finder_api() {
+ if ( is_null( $this->finder_api ) ) {
+ try {
+ $this->finder_api = new FinderSoap();
+ } catch( Exception $e ) {
+ $this->finder_api = null;
+ }
+ }
+
+ if ( is_null( $this->finder_api ) ) {
+ throw new Exception( _x( 'Parcel Finder API not available', 'dhl', 'woocommerce-germanized' ) );
+ }
+
+ return $this->finder_api;
+ }
+
+ public function get_return_api() {
+ if ( is_null( $this->return_api ) ) {
+ try {
+ $this->return_api = new ReturnRest();
+ } catch( Exception $e ) {
+ $this->return_api = null;
+ }
+ }
+
+ if ( is_null( $this->return_api ) ) {
+ throw new Exception( _x( 'Return API not available', 'dhl', 'woocommerce-germanized' ) );
+ }
+
+ return $this->return_api;
+ }
+
+ public function get_parcel_api() {
+ if ( is_null( $this->parcel_api ) ) {
+ try {
+ $this->parcel_api = new ParcelRest();
+ } catch( Exception $e ) {
+ $this->parcel_api = null;
+ }
+ }
+
+ if ( is_null( $this->parcel_api ) ) {
+ throw new Exception( _x( 'Parcel API not available', 'dhl', 'woocommerce-germanized' ) );
+ }
+
+ return $this->parcel_api;
+ }
+
+ public function get_country_code() {
+ return $this->country_code;
+ }
+
+ public function test_connection() {
+ return $this->get_label_api()->test_connection();
+ }
+
+ public function get_parcel_location( $address, $types = array() ) {
+ return $this->get_finder_api()->get_parcel_location( $address, $types );
+ }
+
+ public function get_return_label( &$label ) {
+ return $this->get_return_api()->get_return_label( $label );
+ }
+
+ public function get_label( &$label ) {
+ return $this->get_label_api()->get_label( $label );
+ }
+
+ public function delete_label( &$label ) {
+ return $this->get_label_api()->delete_label( $label );
+ }
+
+ protected function is_working_day( $datetime ) {
+ $is_working_day = ( in_array( $datetime->format( 'Y-m-d' ), Package::get_holidays( 'DE' ) ) ) ? false : true;
+
+ if ( $is_working_day ) {
+ /**
+ * Filter to decide whether DHL should consider saturday as a working day
+ * for preferred day calculation or not.
+ *
+ * @param boolean $is_working_day True if saturday should be considered a working day.
+ *
+ * @since 3.0.0
+ * @package Vendidero/Germanized/DHL
+ */
+ if ( apply_filters( 'woocommerce_gzd_dhl_consider_saturday_as_working_day', true ) ) {
+ $is_working_day = $datetime->format( 'N' ) > 6 ? false : true;
+ } else {
+ $is_working_day = $datetime->format( 'N' ) > 5 ? false : true;
+ }
+ }
+
+ return $is_working_day;
+ }
+
+ /**
+ * This method calculates the starting date for the preferred day time option
+ * and calls the DHL API to retrieve days and times to be chosen by the user in the frontend.
+ *
+ * Starting date calculation works as follows:
+ * 1. If preparation days are set -> add x working days to the current date
+ * 2. If current time is greater than cutoff time -> add one working day
+ * 3. If excluded working days have been chosen -> add x working days
+ * 4. Statically add 2 days for DHL
+ *
+ * @param $postcode
+ * @param string $cutoff_time
+ *
+ * @return array
+ * @throws Exception
+ */
+ public function get_preferred_available_days( $postcode, $cutoff_time = '' ) {
+ $exclude_working_days = wc_gzd_dhl_get_excluded_working_days();
+
+ // Always exclude Sunday
+ $exclude_working_days = array_merge( $exclude_working_days, array( 'sun' ) );
+
+ // Check if every day is excluded -> prevent infinite loops
+ if ( sizeof( $exclude_working_days ) >= 7 ) {
+ return array();
+ }
+
+ $preparation_days = ParcelServices::get_preferred_day_preparation_days();
+ $cutoff_time = empty( $cutoff_time ) ? ParcelServices::get_preferred_day_cutoff_time() : $cutoff_time;
+ $account_num = Package::get_setting( 'account_number' );
+
+ $tz_obj = new DateTimeZone( 'Europe/Berlin' );
+ $starting_date = new DateTime( "now", $tz_obj );
+
+ // Add preparation days
+ if ( ! empty( $preparation_days ) ) {
+ $days_added = 0;
+
+ while ( ! $this->is_working_day( $starting_date ) || $days_added < $preparation_days ) {
+ $starting_date->add( new DateInterval('P1D' ) );
+ $days_added++;
+ }
+ }
+
+ // In case current date lies after cutoff time -> add one working day
+ if ( $starting_date->format( 'Hi' ) > str_replace( ':', '', $cutoff_time ) ) {
+ while ( ! $this->is_working_day( $starting_date ) ) {
+ $starting_date->add( new DateInterval('P1D' ) );
+ break;
+ }
+ }
+
+ // Add days as long as starting date is excluded or is not a working day
+ while ( in_array( strtolower( $starting_date->format( 'D' ) ), $exclude_working_days ) || ! $this->is_working_day( $starting_date ) ) {
+ $starting_date->add( new DateInterval('P1D' ) );
+ }
+
+ // Add 2 working days (for DHL)
+ $days_added = 0;
+
+ while ( ! $this->is_working_day( $starting_date ) || $days_added < 2 ) {
+ $starting_date->add( new DateInterval('P1D' ) );
+ $days_added++;
+ }
+
+ $args['postcode'] = $postcode;
+ $args['account_num'] = $account_num;
+ $args['start_date'] = $starting_date->format( 'Y-m-d' );
+
+ $preferred_days = array();
+
+ try {
+ $preferred_services = $this->get_parcel_api()->get_services( $args );
+ $preferred_days = $this->get_preferred_days( $preferred_services );
+ } catch( Exception $e ) {
+ throw $e;
+ }
+
+ return $preferred_days;
+ }
+
+ protected function get_preferred_days( $preferred_services ) {
+
+ $day_of_week_arr = array(
+ '1' => _x( 'Mon', 'dhl', 'woocommerce-germanized' ),
+ '2' => _x( 'Tue', 'dhl', 'woocommerce-germanized' ),
+ '3' => _x( 'Wed', 'dhl', 'woocommerce-germanized' ),
+ '4' => _x( 'Thu', 'dhl', 'woocommerce-germanized' ),
+ '5' => _x( 'Fri', 'dhl', 'woocommerce-germanized' ),
+ '6' => _x( 'Sat', 'dhl', 'woocommerce-germanized' ),
+ '7' => _x( 'Sun', 'dhl', 'woocommerce-germanized' )
+ );
+
+ $preferred_days = array();
+
+ $tz_obj = new DateTimeZone( 'Europe/Berlin' );
+
+ if ( isset( $preferred_services->preferredDay->available ) && $preferred_services->preferredDay->available && isset( $preferred_services->preferredDay->validDays ) ) {
+
+ foreach ( $preferred_services->preferredDay->validDays as $days_key => $days_value ) {
+
+ $starting_date = new DateTime( $days_value->start, $tz_obj );
+ $day_of_week = $starting_date->format( 'N' );
+ $week_date = $starting_date->format( 'Y-m-d' );
+
+ $preferred_days[ $week_date ] = $day_of_week_arr[ $day_of_week ];
+ }
+
+ // Add none option
+ array_unshift( $preferred_days, _x( 'None', 'dhl day context', 'woocommerce-germanized' ) );
+ }
+
+ return $preferred_days;
+ }
+}
diff --git a/packages/woocommerce-germanized-dhl/src/Api/ParcelRest.php b/packages/woocommerce-germanized-dhl/src/Api/ParcelRest.php
new file mode 100644
index 000000000..6a0d31069
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/Api/ParcelRest.php
@@ -0,0 +1,50 @@
+ '',
+ 'account_num' => Package::get_setting( 'account_number' ),
+ 'start_date' => '',
+ ) );
+
+ if ( empty( $args['postcode'] ) ) {
+ throw new Exception( _x( 'Please provide the receiver postnumber.', 'dhl', 'woocommerce-germanized' ) );
+ }
+
+ if ( empty( $args['account_num'] ) && ! Package::is_debug_mode() ) {
+ throw new Exception( _x( 'Please set an account in the DHL shipping settings.', 'dhl', 'woocommerce-germanized' ) );
+ }
+
+ if ( empty( $args['start_date'] ) ) {
+ throw new Exception( _x( 'Please provide the shipment start date.', 'dhl', 'woocommerce-germanized' ) );
+ }
+
+ $this->account_num = $args['account_num'];
+
+ return $this->get_request( '/checkout/' . $args['postcode'] . '/availableServices', array( 'startDate' => $args['start_date'] ) );
+ }
+
+ protected function set_header( $authorization = '', $request_type = 'GET', $endpoint = '' ) {
+ parent::set_header();
+
+ if ( ! empty( $authorization ) ) {
+ $this->remote_header['Authorization'] = $authorization;
+ }
+
+ $this->remote_header['X-EKP'] = $this->account_num;
+ }
+}
diff --git a/packages/woocommerce-germanized-dhl/src/Api/Rest.php b/packages/woocommerce-germanized-dhl/src/Api/Rest.php
new file mode 100644
index 000000000..ea417fbb8
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/Api/Rest.php
@@ -0,0 +1,201 @@
+id = $id;
+ }
+
+ /**
+ * Get the id
+ *
+ * @return $id
+ */
+ public function get_id() {
+ return $this->id;
+ }
+
+ protected function get_auth() {
+ return $this->get_basic_auth_encode( Package::get_cig_user(), Package::get_cig_password() );
+ }
+
+ public function get_request( $endpoint = '', $query_args = array(), $content_type = 'json' ) {
+ $api_url = $this->get_base_url();
+
+ $this->set_header( $this->get_auth(), 'GET', $endpoint );
+
+ $wp_request_url = add_query_arg( $query_args, $api_url . $endpoint );
+ $wp_request_headers = $this->get_header();
+
+ Package::log( 'GET URL: ' . $wp_request_url );
+
+ $wp_dhl_rest_response = wp_remote_get(
+ $wp_request_url,
+ array(
+ 'headers' => $wp_request_headers,
+ 'timeout' => 30
+ )
+ );
+
+ $response_code = wp_remote_retrieve_response_code( $wp_dhl_rest_response );
+ $response_body = wp_remote_retrieve_body( $wp_dhl_rest_response );
+
+ if ( 'json' === $content_type ) {
+ $response_body = json_decode( $response_body );
+ }
+
+ Package::log( 'GET Response Code: ' . $response_code );
+ Package::log( 'GET Response Body: ' . print_r( $response_body, true ) );
+
+ $this->handle_get_response( $response_code, $response_body );
+
+ return $response_body;
+ }
+
+ protected function handle_get_response( $response_code, $response_body ) {
+ switch ( $response_code ) {
+ case '200':
+ case '201':
+ break;
+ case '400':
+ $error_message = str_replace('/', ' / ', isset( $response_body->statusText ) ? $response_body->statusText : '' );
+ throw new Exception( _x( '400 - ', 'dhl', 'woocommerce-germanized' ) . $error_message );
+ break;
+ case '401':
+ throw new Exception( _x( '401 - Unauthorized Access - Invalid token or Authentication Header parameter', 'dhl', 'woocommerce-germanized' ) );
+ break;
+ case '408':
+ throw new Exception( _x( '408 - Request Timeout', 'dhl', 'woocommerce-germanized' ) );
+ break;
+ case '429':
+ throw new Exception( _x( '429 - Too many requests in given amount of time', 'dhl', 'woocommerce-germanized' ) );
+ break;
+ case '503':
+ throw new Exception( _x( '503 - Service Unavailable', 'dhl', 'woocommerce-germanized' ) );
+ break;
+ default:
+ if ( empty( $response_body->statusText ) ) {
+ $error_message = _x( 'GET error or timeout occured. Please try again later.', 'dhl', 'woocommerce-germanized' );
+ } else {
+ $error_message = str_replace('/', ' / ', $response_body->statusText);
+ }
+
+ Package::log( 'GET Error: ' . $response_code . ' - ' . $error_message );
+
+ throw new Exception( $response_code .' - ' . $error_message );
+ break;
+ }
+ }
+
+ public function get_base_url() {
+ return Package::get_rest_url();
+ }
+
+ public function post_request( $endpoint = '', $query_args = array() ) {
+ $api_url = $this->get_base_url();
+
+ $this->set_header( $this->get_auth(), 'POST', $endpoint );
+
+ $wp_request_url = $api_url . $endpoint;
+ $wp_request_headers = $this->get_header();
+
+ Package::log( 'POST URL: ' . $wp_request_url );
+
+ $wp_dhl_rest_response = wp_remote_post(
+ $wp_request_url,
+ array(
+ 'headers' => $wp_request_headers,
+ 'timeout' => 100,
+ 'body' => $query_args,
+ )
+ );
+
+ $response_code = wp_remote_retrieve_response_code( $wp_dhl_rest_response );
+ $response_body = json_decode( wp_remote_retrieve_body( $wp_dhl_rest_response ) );
+
+ Package::log( 'POST Response Code: ' . $response_code );
+ Package::log( 'POST Response Body: ' . print_r( $response_body, true ) );
+
+ $this->handle_post_response( $response_code, $response_body );
+
+ return $response_body;
+ }
+
+ protected function handle_post_response( $response_code, $response_body ) {
+ switch ( $response_code ) {
+ case '200':
+ case '201':
+ break;
+ default:
+ if ( empty( $response_body->detail ) ) {
+ $error_message = _x( 'POST error or timeout occured. Please try again later.', 'dhl', 'woocommerce-germanized' );
+ } else {
+ $error_message = $response_body->detail;
+ }
+
+ Package::log( 'POST Error: ' . $response_code . ' - ' . $error_message );
+
+ throw new Exception( $response_code .' - ' . $error_message );
+ break;
+ }
+ }
+
+ protected function get_basic_auth_encode( $user, $pass ) {
+ return 'Basic ' . base64_encode( $user . ':' . $pass );
+ }
+
+ protected function set_header( $authorization = '', $request_type = 'GET', $endpoint = '' ) {
+ $wp_version = get_bloginfo( 'version' );
+ $wc_version = defined( 'WC_Version' ) ? WC_Version : '';
+
+ $dhl_header['Content-Type'] = 'application/json';
+ $dhl_header['Accept'] = 'application/json';
+ $dhl_header['Authorization'] = 'Bearer ' . $authorization;
+ $dhl_header['User-Agent'] = 'WooCommerce/'. $wc_version . ' (WordPress/'. $wp_version . ') Germanized-DHL/' . Package::get_version();
+
+ $this->remote_header = $dhl_header;
+ }
+
+ protected function get_header( ) {
+ return $this->remote_header;
+ }
+}
diff --git a/packages/woocommerce-germanized-dhl/src/Api/ReturnRest.php b/packages/woocommerce-germanized-dhl/src/Api/ReturnRest.php
new file mode 100644
index 000000000..9d936020b
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/Api/ReturnRest.php
@@ -0,0 +1,174 @@
+create_return_label( $label );
+ }
+
+ /**
+ * @param \Vendidero\Germanized\DHL\Label\ReturnLabel $label
+ */
+ protected function get_request_args( $label ) {
+ $shipment = $label->get_shipment();
+ $countries = WC()->countries->get_countries();
+ $country_name = $label->get_sender_country();
+
+ if ( ! $shipment ) {
+ throw new Exception( sprintf( _x( 'Could not fetch shipment %d.', 'dhl', 'woocommerce-germanized' ), $label->get_shipment_id() ) );
+ }
+
+ $order = $shipment->get_order();
+
+ if ( isset( $countries[ $country_name ] ) ) {
+ $country_name = $countries[ $country_name ];
+ }
+
+ $label->get_sender_country();
+
+ $request_args = array(
+ 'receiverId' => $label->get_receiver_id(),
+ "customerReference" => wc_gzd_dhl_get_return_label_customer_reference( $label, $shipment ),
+ "shipmentReference" => '',
+ "senderAddress" => array(
+ 'name1' => $label->get_sender_company() ? $label->get_sender_company() : $label->get_sender_formatted_full_name(),
+ 'name2' => $label->get_sender_company() ? $label->get_sender_formatted_full_name() : '',
+ /**
+ * By default the name3 parameter is used to transmit the additional
+ * address field to the DHL API. You may adjust the field value by using this filter.
+ *
+ * @param string $value The field value.
+ * @param \Vendidero\Germanized\DHL\Label\ReturnLabel $label The label instance.
+ *
+ * @since 3.0.3
+ * @package Vendidero/Germanized/DHL
+ */
+ 'name3' => apply_filters( 'woocommerce_gzd_dhl_return_label_api_sender_name3', $label->get_sender_address_addition(), $label ),
+ 'streetName' => $label->get_sender_street(),
+ 'houseNumber' => wc_gzd_dhl_get_return_label_sender_street_number( $label ),
+ 'postCode' => $label->get_sender_postcode(),
+ 'city' => $label->get_sender_city(),
+ 'country' => array(
+ 'countryISOCode' => Package::get_country_iso_alpha3( $label->get_sender_country() ),
+ 'country' => $country_name,
+ 'state' => $label->get_sender_state(),
+ ),
+ ),
+ 'email' => Package::get_setting( 'return_email' ),
+ 'telephoneNumber' => Package::get_setting( 'return_phone' ),
+ "weightInGrams" => wc_get_weight( $label->get_weight(), 'g', 'kg' ),
+ 'value' => $shipment->get_total(),
+ 'returnDocumentType' => 'SHIPMENT_LABEL'
+ );
+
+ if ( Package::is_crossborder_shipment( $label->get_sender_country() ) ) {
+ $items = array();
+ $customs_data = wc_gzd_dhl_get_shipment_customs_data( $label );
+ $shipment_items = $shipment->get_items();
+
+ foreach( $customs_data['items'] as $key => $customs_item ) {
+ $shipment_item = $shipment_items[ $key ];
+
+ $items[] = array(
+ 'positionDescription' => $customs_item['description'],
+ 'count' => $customs_item['quantity'],
+ /**
+ * Total weight per row
+ */
+ 'weightInGrams' => intval( wc_get_weight( $customs_item['weight_in_kg'], 'g', 'kg' ) ),
+ /**
+ * Total value per row
+ */
+ 'values' => $customs_item['value'],
+ 'originCountry' => $customs_item['origin_code'],
+ 'articleReference' => apply_filters( 'woocommerce_gzd_dhl_retoure_customs_article_reference', $customs_item['category'], $shipment_item, $label ),
+ 'tarifNumber' => $customs_item['tariff_number'],
+ );
+ }
+
+ $request_args['customsDocument'] = apply_filters( 'woocommerce_gzd_dhl_retoure_customs_data', array(
+ 'currency' => $order ? $order->get_currency() : 'EUR',
+ 'originalShipmentNumber' => $shipment->get_order_number(),
+ 'originalOperator' => $shipment->get_shipping_provider(),
+ 'positions' => $items,
+ ), $label );
+ }
+
+ return $request_args;
+ }
+
+ public function create_return_label( &$label ) {
+ try {
+ $request_args = $this->get_request_args( $label );
+ $result = $this->post_request( '/returns/', json_encode( $request_args ) );
+
+ Package::log( '"returns" called with: ' . print_r( $request_args, true ) );
+ } catch ( Exception $e ) {
+ Package::log( 'Response Error: ' . $e->getMessage() );
+ throw $e;
+ }
+
+ return $this->update_return_label( $label, $result );
+ }
+
+ /**
+ * @param ReturnLabel $label
+ * @param $response_body
+ *
+ * @return mixed
+ * @throws Exception
+ */
+ protected function update_return_label( $label, $response_body ) {
+ try {
+ if ( isset( $response_body->shipmentNumber ) ) {
+ $label->set_number( $response_body->shipmentNumber );
+ }
+
+ $default_file = base64_decode( $response_body->labelData );
+
+ // Store the downloaded label as default file
+ $path = $label->upload_label_file( $default_file );
+
+ if ( ! $path ) {
+ throw new Exception( 'Error while uploading the return label' );
+ }
+ } catch( Exception $e ) {
+ // Delete the label dues to errors.
+ $label->delete();
+
+ throw new Exception( _x( 'Error while creating and uploading the label', 'dhl', 'woocommerce-germanized' ) );
+ }
+
+ return $label;
+ }
+
+ protected function get_retoure_auth() {
+ return base64_encode( Package::get_retoure_api_user() . ':' . Package::get_retoure_api_signature() );
+ }
+
+ protected function set_header( $authorization = '', $request_type = 'GET', $endpoint = '' ) {
+ parent::set_header();
+
+ if ( ! empty( $authorization ) ) {
+ $this->remote_header['Authorization'] = $authorization;
+ }
+
+ $this->remote_header['DPDHL-User-Authentication-Token'] = $this->get_retoure_auth();
+ }
+}
diff --git a/packages/woocommerce-germanized-dhl/src/Api/Soap.php b/packages/woocommerce-germanized-dhl/src/Api/Soap.php
new file mode 100644
index 000000000..8a7dc583f
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/Api/Soap.php
@@ -0,0 +1,84 @@
+SOAPClient is required. Please contact your host and make sure that SOAPClient is installed .', 'dhl', 'woocommerce-germanize-dhl' ), 'https://www.php.net/manual/class.soapclient.php', admin_url( 'admin.php?page=wc-status' ) ) );
+ }
+
+ $this->soap_auth = new AuthSoap( $wsdl_link );
+ } catch ( Exception $e ) {
+ throw $e;
+ }
+ }
+
+ protected function get_auth_api() {
+ return $this->soap_auth;
+ }
+
+ abstract public function get_access_token();
+
+ protected function walk_recursive_remove( array $array ) {
+ foreach ( $array as $k => $v ) {
+
+ if ( is_array( $v ) ) {
+ $array[ $k ] = $this->walk_recursive_remove( $v );
+ }
+
+ // Explicitly allow street_number fields to equal 0
+ if ( empty( $v ) && ( ! in_array( $k, array( 'minorRelease', 'streetNumber', 'houseNumber' ) ) ) ) {
+ unset( $array[ $k ] );
+ }
+ }
+
+ return $array;
+ }
+}
diff --git a/packages/woocommerce-germanized-dhl/src/Install.php b/packages/woocommerce-germanized-dhl/src/Install.php
new file mode 100644
index 000000000..96c4f9bb1
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/Install.php
@@ -0,0 +1,228 @@
+ indicate update necessary
+ $needs_settings_update = ( get_option( 'woocommerce_gzd_dhl_enable' ) || get_option( 'woocommerce_gzd_deutsche_post_enable' ) ) && ! get_option( 'woocommerce_gzd_migrated_settings' );
+ } else {
+ update_option( 'woocommerce_gzd_dhl_version', Package::get_version() );
+ }
+
+ if ( $needs_settings_update ) {
+ self::migrate_settings();
+ }
+ }
+
+ private static function migrate_settings() {
+ global $wpdb;
+
+ /**
+ * Make sure to reload shipping providers to make sure our classes were registered accordingly as the
+ * install script may be called later than on plugins loaded.
+ */
+ Helper::instance()->load_shipping_providers();
+
+ $plugin_options = $wpdb->get_results( "SELECT option_name FROM $wpdb->options WHERE option_name LIKE 'woocommerce_gzd_dhl_%' OR option_name LIKE 'woocommerce_gzd_deutsche_post_%'" );
+ $dhl = wc_gzd_get_shipping_provider( 'dhl' );
+ $deutsche_post = wc_gzd_get_shipping_provider( 'deutsche_post' );
+ $excluded_options = array(
+ 'woocommerce_gzd_dhl_upload_dir_suffix',
+ 'woocommerce_gzd_dhl_enable',
+ 'woocommerce_gzd_dhl_enable_internetmarke',
+ 'woocommerce_gzd_dhl_internetmarke_enable',
+ 'woocommerce_gzd_dhl_version'
+ );
+
+ /**
+ * Error while retrieving shipping provider instance
+ */
+ if ( ! is_a( $dhl, '\Vendidero\Germanized\DHL\ShippingProvider\DHL' ) || ! is_a( $deutsche_post, '\Vendidero\Germanized\DHL\ShippingProvider\DeutschePost' ) ) {
+ return false;
+ }
+
+ foreach( $plugin_options as $option ) {
+ $option_name = $option->option_name;
+
+ if ( in_array( $option_name, $excluded_options ) ) {
+ continue;
+ }
+
+ $option_value = get_option( $option->option_name, '' );
+ $is_dp = strpos( $option_name, '_im_' ) !== false || strpos( $option_name, '_internetmarke_' ) !== false || strpos( $option_name, '_deutsche_post_' ) !== false;
+
+ if ( ! $is_dp ) {
+ $option_name_clean = str_replace( 'woocommerce_gzd_dhl_', '', $option_name );
+
+ if ( strstr( $option_name_clean, 'shipper_' ) || strstr( $option_name_clean, 'return_address_' ) ) {
+ continue;
+ } elseif( 'parcel_pickup_map_api_key' === $option_name_clean ) {
+ self::update_provider_setting( $dhl, 'parcel_pickup_map_api_password', $option_value );
+ } else {
+ self::update_provider_setting( $dhl, $option_name_clean, $option_value );
+ }
+ } else {
+ $option_name_clean = str_replace( 'woocommerce_gzd_deutsche_post_', '', $option_name );
+ $option_name_clean = str_replace( 'woocommerce_gzd_dhl_', '', $option_name_clean );
+ $option_name_clean = str_replace( 'deutsche_post_', '', $option_name_clean );
+ $option_name_clean = str_replace( 'im_', '', $option_name_clean );
+
+ self::update_provider_setting( $deutsche_post, $option_name_clean, $option_value );
+ }
+ }
+
+ $deutsche_post->set_label_default_shipment_weight( get_option( 'woocommerce_gzd_dhl_label_default_shipment_weight' ) );
+ $deutsche_post->set_label_minimum_shipment_weight( get_option( 'woocommerce_gzd_dhl_label_minimum_shipment_weight' ) );
+
+ $dhl->save();
+ $deutsche_post->save();
+
+ $shipper_name = self::get_address_name_parts( 'shipper' );
+
+ // Update address data
+ $shipper_address = array(
+ 'first_name' => $shipper_name['first_name'],
+ 'last_name' => $shipper_name['last_name'],
+ 'company' => get_option( 'woocommerce_gzd_dhl_shipper_company' ),
+ 'address_1' => get_option( 'woocommerce_gzd_dhl_shipper_street' ) . ' ' . get_option( 'woocommerce_gzd_dhl_shipper_street_no' ),
+ 'postcode' => get_option( 'woocommerce_gzd_dhl_shipper_postcode' ),
+ 'country' => get_option( 'woocommerce_gzd_dhl_shipper_country' ),
+ 'city' => get_option( 'woocommerce_gzd_dhl_shipper_city' ),
+ 'phone' => get_option( 'woocommerce_gzd_dhl_shipper_phone' ),
+ 'email' => get_option( 'woocommerce_gzd_dhl_shipper_email' ),
+ );
+
+ $shipper_address = array_filter( $shipper_address );
+
+ foreach( $shipper_address as $key => $value ) {
+ update_option( 'woocommerce_gzd_shipments_shipper_address_' . $key, $value );
+ }
+
+ $return_name = self::get_address_name_parts( 'return_address' );
+
+ $return_address = array(
+ 'first_name' => $return_name['first_name'],
+ 'last_name' => $return_name['last_name'],
+ 'company' => get_option( 'woocommerce_gzd_dhl_return_address_company' ),
+ 'address_1' => get_option( 'woocommerce_gzd_dhl_return_address_street' ) . ' ' . get_option( 'woocommerce_gzd_dhl_return_address_street_no' ),
+ 'postcode' => get_option( 'woocommerce_gzd_dhl_return_address_postcode' ),
+ 'country' => get_option( 'woocommerce_gzd_dhl_return_address_country' ),
+ 'city' => get_option( 'woocommerce_gzd_dhl_return_address_city' ),
+ 'phone' => get_option( 'woocommerce_gzd_dhl_return_address_phone' ),
+ 'email' => get_option( 'woocommerce_gzd_dhl_return_address_email' ),
+ );
+
+ $return_address = array_filter( $return_address );
+
+ foreach( $return_address as $key => $value ) {
+ update_option( 'woocommerce_gzd_shipments_return_address_' . $key, $value );
+ }
+
+ update_option( 'woocommerce_gzd_migrated_settings', 'yes' );
+
+ return true;
+ }
+
+ protected static function get_address_name_parts( $address_type = 'shipper' ) {
+ $sender_name = explode( " ", get_option( "woocommerce_gzd_dhl_{$address_type}_name" ) );
+ $sender_name_first = $sender_name;
+ $sender_first_name = implode( ' ', array_splice( $sender_name_first, 0, ( sizeof( $sender_name ) - 1 ) ) );
+ $sender_last_name = $sender_name[ sizeof( $sender_name ) - 1 ];
+
+ return array(
+ 'first_name' => $sender_first_name,
+ 'last_name' => $sender_last_name
+ );
+ }
+
+ /**
+ * @param Simple $provider
+ * @param $key
+ * @param $value
+ */
+ protected static function update_provider_setting( $provider, $key, $value ) {
+ $provider->update_setting( $key, $value );
+ }
+
+ private static function create_db() {
+ global $wpdb;
+ $wpdb->hide_errors();
+ require_once ABSPATH . 'wp-admin/includes/upgrade.php';
+ dbDelta( self::get_schema() );
+ }
+
+ private static function get_schema() {
+ global $wpdb;
+
+ $collate = '';
+
+ if ( $wpdb->has_cap( 'collation' ) ) {
+ $collate = $wpdb->get_charset_collate();
+ }
+
+ $tables = "
+CREATE TABLE {$wpdb->prefix}woocommerce_gzd_dhl_im_products (
+ product_id BIGINT UNSIGNED NOT NULL auto_increment,
+ product_im_id BIGINT UNSIGNED NOT NULL,
+ product_code INT(16) NOT NULL,
+ product_name varchar(150) NOT NULL DEFAULT '',
+ product_slug varchar(150) NOT NULL DEFAULT '',
+ product_version INT(5) NOT NULL DEFAULT 1,
+ product_annotation varchar(500) NOT NULL DEFAULT '',
+ product_description varchar(500) NOT NULL DEFAULT '',
+ product_information_text TEXT NOT NULL DEFAULT '',
+ product_type varchar(50) NOT NULL DEFAULT 'sales',
+ product_destination varchar(20) NOT NULL DEFAULT 'national',
+ product_price INT(8) NOT NULL,
+ product_length_min INT(8) NULL,
+ product_length_max INT(8) NULL,
+ product_length_unit VARCHAR(8) NULL,
+ product_width_min INT(8) NULL,
+ product_width_max INT(8) NULL,
+ product_width_unit VARCHAR(8) NULL,
+ product_height_min INT(8) NULL,
+ product_height_max INT(8) NULL,
+ product_height_unit VARCHAR(8) NULL,
+ product_weight_min INT(8) NULL,
+ product_weight_max INT(8) NULL,
+ product_weight_unit VARCHAR(8) NULL,
+ product_parent_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
+ product_service_count INT(3) NOT NULL DEFAULT 0,
+ product_is_wp_int INT(1) NOT NULL DEFAULT 0,
+ PRIMARY KEY (product_id),
+ KEY product_im_id (product_im_id),
+ KEY product_code (product_code)
+) $collate;
+CREATE TABLE {$wpdb->prefix}woocommerce_gzd_dhl_im_product_services (
+ product_service_id BIGINT UNSIGNED NOT NULL auto_increment,
+ product_service_product_id BIGINT UNSIGNED NOT NULL,
+ product_service_product_parent_id BIGINT UNSIGNED NOT NULL,
+ product_service_slug VARCHAR(20) NOT NULL DEFAULT '',
+ PRIMARY KEY (product_service_id),
+ KEY product_service_product_id (product_service_product_id),
+ KEY product_service_product_parent_id (product_service_product_parent_id)
+) $collate;";
+
+ return $tables;
+ }
+}
diff --git a/packages/woocommerce-germanized-dhl/src/Label/DHL.php b/packages/woocommerce-germanized-dhl/src/Label/DHL.php
new file mode 100644
index 000000000..f1239fddf
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/Label/DHL.php
@@ -0,0 +1,389 @@
+ '',
+ 'export_path' => '',
+ 'preferred_day' => '',
+ 'preferred_location' => '',
+ 'preferred_neighbor' => '',
+ 'ident_date_of_birth' => '',
+ 'ident_min_age' => '',
+ 'visual_min_age' => '',
+ 'email_notification' => 'no',
+ 'has_inlay_return' => 'no',
+ 'codeable_address_only' => 'no',
+ 'duties' => '',
+ 'return_address' => array(),
+ 'cod_total' => 0,
+ 'cod_includes_additional_total' => 'no',
+ );
+
+ public function get_type() {
+ return 'simple';
+ }
+
+ public function get_shipping_provider( $context = 'view' ) {
+ return 'dhl';
+ }
+
+ public function get_return_address( $context = 'view' ) {
+ return $this->get_prop( 'return_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_return_address_prop( $prop, $context = 'view' ) {
+ $value = $this->get_address_prop( $prop, 'return_address', $context );
+
+ // Load from settings
+ if ( is_null( $value ) ) {
+ $value = Package::get_setting( 'return_' . $prop );
+ }
+
+ return $value;
+ }
+
+ public function get_return_street( $context = 'view' ) {
+ return $this->get_return_address_prop( 'street', $context );
+ }
+
+ public function get_return_street_number( $context = 'view' ) {
+ return $this->get_return_address_prop( 'street_number', $context );
+ }
+
+ public function get_return_company( $context = 'view' ) {
+ return $this->get_return_address_prop( 'company', $context );
+ }
+
+ public function get_return_name( $context = 'view' ) {
+ return $this->get_return_address_prop( 'name', $context );
+ }
+
+ public function get_return_formatted_full_name() {
+ return sprintf( _x( '%1$s', 'dhl full name', 'woocommerce-germanized' ), $this->get_return_name() );
+ }
+
+ public function get_return_postcode( $context = 'view' ) {
+ return $this->get_return_address_prop( 'postcode', $context );
+ }
+
+ public function get_return_city( $context = 'view' ) {
+ return $this->get_return_address_prop( 'city', $context );
+ }
+
+ public function get_return_state( $context = 'view' ) {
+ return $this->get_return_address_prop( 'state', $context );
+ }
+
+ public function get_return_country( $context = 'view' ) {
+ return $this->get_return_address_prop( 'country', $context );
+ }
+
+ public function get_return_phone( $context = 'view' ) {
+ return $this->get_return_address_prop( 'phone', $context );
+ }
+
+ public function get_return_email( $context = 'view' ) {
+ return $this->get_return_address_prop( 'email', $context );
+ }
+
+ public function get_cod_total( $context = 'view' ) {
+ return $this->get_prop( 'cod_total', $context );
+ }
+
+ public function get_cod_includes_additional_total( $context = 'view' ) {
+ return $this->get_prop( 'cod_includes_additional_total', $context );
+ }
+
+ public function cod_includes_additional_total( $context = 'view' ) {
+ return $this->get_cod_includes_additional_total() ? true : false;
+ }
+
+ public function get_duties( $context = 'view' ) {
+ return $this->get_prop( 'duties', $context );
+ }
+
+ public function get_preferred_day( $context = 'view' ) {
+ return $this->get_prop( 'preferred_day', $context );
+ }
+
+ public function get_preferred_location( $context = 'view' ) {
+ return $this->get_prop( 'preferred_location', $context );
+ }
+
+ public function get_preferred_neighbor( $context = 'view' ) {
+ return $this->get_prop( 'preferred_neighbor', $context );
+ }
+
+ public function get_ident_date_of_birth( $context = 'view' ) {
+ return $this->get_prop( 'ident_date_of_birth', $context );
+ }
+
+ public function get_ident_min_age( $context = 'view' ) {
+ return $this->get_prop( 'ident_min_age', $context );
+ }
+
+ public function get_visual_min_age( $context = 'view' ) {
+ return $this->get_prop( 'visual_min_age', $context );
+ }
+
+ public function get_email_notification( $context = 'view' ) {
+ return $this->get_prop( 'email_notification', $context );
+ }
+
+ public function has_email_notification() {
+ return ( true === $this->get_email_notification() );
+ }
+
+ public function get_has_inlay_return( $context = 'view' ) {
+ return $this->get_prop( 'has_inlay_return', $context );
+ }
+
+ public function has_inlay_return() {
+ $products = wc_gzd_dhl_get_inlay_return_products();
+
+ return ( true === $this->get_has_inlay_return() && in_array( $this->get_product_id(), $products ) );
+ }
+
+ /**
+ * Returns a directly linked return label.
+ *
+ * @return bool|DHLInlayReturn
+ */
+ public function get_inlay_return_label() {
+ $children = $this->get_children();
+
+ if ( ! empty( $children ) && is_a( $children[0], '\Vendidero\Germanized\DHL\Label\DHLInlayReturn' ) ) {
+ return $children[0];
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks whether the label has a directly linked return label.
+ *
+ * @return bool
+ */
+ public function has_inlay_return_label() {
+ $label = $this->get_inlay_return_label();
+
+ return $label ? true : false;
+ }
+
+ public function get_codeable_address_only( $context = 'view' ) {
+ return $this->get_prop( 'codeable_address_only', $context );
+ }
+
+ public function codeable_address_only() {
+ return ( true === $this->get_codeable_address_only() );
+ }
+
+ public function set_return_address( $value ) {
+ $this->set_prop( 'return_address', empty( $value ) ? array() : (array) $value );
+ }
+
+ public function set_cod_total( $value ) {
+ $value = wc_format_decimal( $value );
+
+ if ( ! is_numeric( $value ) ) {
+ $value = 0;
+ }
+
+ $this->set_prop( 'cod_total', $value );
+ }
+
+ public function set_cod_includes_additional_total( $value ) {
+ $this->set_prop( 'cod_includes_additional_total', wc_string_to_bool( $value ) );
+ }
+
+ public function set_duties( $duties ) {
+ $this->set_prop( 'duties', $duties );
+ }
+
+ public function set_preferred_day( $day ) {
+ $this->set_date_prop( 'preferred_day', $day );
+ }
+
+ public function set_preferred_location( $location ) {
+ $this->set_prop( 'preferred_location', $location );
+ }
+
+ public function set_preferred_neighbor( $neighbor ) {
+ $this->set_prop( 'preferred_neighbor', $neighbor );
+ }
+
+ public function set_email_notification( $value ) {
+ $this->set_prop( 'email_notification', wc_string_to_bool( $value ) );
+ }
+
+ public function set_has_inlay_return( $value ) {
+ $this->set_prop( 'has_inlay_return', wc_string_to_bool( $value ) );
+ }
+
+ public function set_codeable_address_only( $value ) {
+ $this->set_prop( 'codeable_address_only', wc_string_to_bool( $value ) );
+ }
+
+ public function set_ident_date_of_birth( $date ) {
+ $this->set_date_prop( 'ident_date_of_birth', $date );
+ }
+
+ public function set_ident_min_age( $age ) {
+ $this->set_prop( 'ident_min_age', $age );
+ }
+
+ public function set_visual_min_age( $age ) {
+ $this->set_prop( 'visual_min_age', $age );
+ }
+
+ /**
+ * @return \WP_Error|true
+ */
+ public function fetch() {
+ $result = new \WP_Error();
+
+ try {
+ Package::get_api()->get_label( $this );
+ } catch( \Exception $e ) {
+ $errors = explode(PHP_EOL, $e->getMessage() );
+
+ foreach( $errors as $error ) {
+ $result->add( 'dhl-api-error', $error );
+ }
+ }
+
+ if ( wc_gzd_dhl_wp_error_has_errors( $result ) ) {
+ return $result;
+ } else {
+ return true;
+ }
+ }
+
+ public function delete( $force_delete = false ) {
+ if ( $api = Package::get_api() ) {
+ try {
+ $api->get_label_api()->delete_label( $this );
+ } catch( \Exception $e ) {}
+ }
+
+ return parent::delete( $force_delete );
+ }
+
+ public function get_additional_file_types() {
+ return array(
+ 'default',
+ 'export'
+ );
+ }
+
+ public function get_filename( $file_type = '' ) {
+ if ( 'default' === $file_type ) {
+ return $this->get_default_filename();
+ } elseif( 'export' === $file_type ) {
+ return $this->get_export_filename();
+ } else {
+ return parent::get_filename( $file_type );
+ }
+ }
+
+ public function get_file( $file_type = '' ) {
+ if ( 'default' === $file_type ) {
+ return $this->get_default_file();
+ } elseif( 'export' === $file_type ) {
+ return $this->get_export_file();
+ } else {
+ return parent::get_file( $file_type );
+ }
+ }
+
+ public function get_path( $context = 'view', $file_type = '' ) {
+ if ( 'default' === $file_type ) {
+ return $this->get_default_path( $context );
+ } elseif( 'export' === $file_type ) {
+ return $this->get_export_path( $context );
+ } else {
+ return parent::get_path( $context, $file_type );
+ }
+ }
+
+ public function set_path( $path, $file_type = '' ) {
+ if ( 'default' === $file_type ) {
+ $this->set_default_path( $path );
+ } elseif( 'export' === $file_type ) {
+ $this->set_export_path( $path );
+ } else {
+ parent::set_path( $path, $file_type );
+ }
+ }
+
+ public function get_default_file() {
+ if ( ! $path = $this->get_default_path() ) {
+ return false;
+ }
+
+ return $this->get_file_by_path( $path );
+ }
+
+ public function get_default_filename() {
+ if ( ! $path = $this->get_default_path() ) {
+ return $this->get_new_filename( 'default' );
+ }
+
+ return basename( $path );
+ }
+
+ public function get_export_file() {
+ if ( ! $path = $this->get_export_path() ) {
+ return false;
+ }
+
+ return $this->get_file_by_path( $path );
+ }
+
+ public function get_export_filename() {
+ if ( ! $path = $this->get_export_path() ) {
+ return $this->get_new_filename( 'export' );
+ }
+
+ return basename( $path );
+ }
+
+ public function set_default_path( $path ) {
+ $this->set_prop( 'default_path', $path );
+ }
+
+ public function set_export_path( $path ) {
+ $this->set_prop( 'export_path', $path );
+ }
+
+ public function get_default_path( $context = 'view' ) {
+ return $this->get_prop( 'default_path', $context );
+ }
+
+ public function get_export_path( $context = 'view' ) {
+ return $this->get_prop( 'export_path', $context );
+ }
+}
diff --git a/packages/woocommerce-germanized-dhl/src/Label/DHLInlayReturn.php b/packages/woocommerce-germanized-dhl/src/Label/DHLInlayReturn.php
new file mode 100644
index 000000000..28f733b88
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/Label/DHLInlayReturn.php
@@ -0,0 +1,15 @@
+ '',
+ 'sender_address' => array()
+ );
+
+ protected function get_hook_prefix() {
+ return 'woocommerce_gzd_dhl_return_label_get_';
+ }
+
+ public function get_type() {
+ return 'return';
+ }
+
+ public function get_shipping_provider( $context = 'view' ) {
+ return 'dhl';
+ }
+
+ public function get_receiver_id() {
+ $slug = $this->get_receiver_slug();
+ $id = '';
+
+ if ( $has_id = Package::get_return_receiver_by_slug( $slug ) ) {
+ $id = $has_id['id'];
+ }
+
+ /**
+ * Returns the return receiver id for a certain DHL label.
+ *
+ * The dynamic portion of the hook name, `$this->get_hook_prefix()` constructs an individual
+ * hook name which uses `woocommerce_gzd_dhl_return_label_get_` as a prefix.
+ *
+ * Example hook name: `woocommerce_gzd_shipments_dhl_return_label_get_receiver_id`
+ *
+ * @param string $id The receiver id.
+ * @param ReturnLabel $label The return label
+ *
+ * @package Vendidero/Germanized/DHL
+ */
+ return apply_filters( "{$this->get_hook_prefix()}receiver_id", $id, $this );
+ }
+
+ public function get_receiver_slug( $context = 'view' ) {
+ return $this->get_prop( 'receiver_slug', $context );
+ }
+
+ public function set_receiver_slug( $receiver_slug ) {
+ $this->set_prop( 'receiver_slug', $receiver_slug );
+ }
+
+ /**
+ * @return \WP_Error|true
+ */
+ public function fetch() {
+ $result = new \WP_Error();
+
+ try {
+ Package::get_api()->get_return_label( $this );
+ } catch( \Exception $e ) {
+ $errors = explode(PHP_EOL, $e->getMessage() );
+
+ foreach( $errors as $error ) {
+ $result->add( 'dhl-api-error', $error );
+ }
+ }
+
+ if ( wc_gzd_dhl_wp_error_has_errors( $result ) ) {
+ return $result;
+ } else {
+ return true;
+ }
+ }
+}
diff --git a/packages/woocommerce-germanized-dhl/src/Label/DeutschePost.php b/packages/woocommerce-germanized-dhl/src/Label/DeutschePost.php
new file mode 100644
index 000000000..0d395500d
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/Label/DeutschePost.php
@@ -0,0 +1,201 @@
+ '',
+ 'shop_order_id' => '',
+ 'stamp_total' => 0,
+ 'voucher_id' => '',
+ 'original_url' => '',
+ 'manifest_url' => '',
+ 'wp_int_awb' => '',
+ 'wp_int_barcode' => '',
+ );
+
+ public function __construct( $data = 0, $legacy = false ) {
+ if ( $legacy ) {
+ $this->extra_data['additional_services'] = array();
+ }
+
+ parent::__construct( $data, $legacy );
+ }
+
+ public function get_type() {
+ return 'simple';
+ }
+
+ public function get_shipping_provider( $context = 'view' ) {
+ return 'deutsche_post';
+ }
+
+ public function get_number( $context = 'view' ) {
+ $number = parent::get_number( $context );
+
+ return $number;
+ }
+
+ public function get_page_format( $context = 'view' ) {
+ return $this->get_prop( 'page_format', $context );
+ }
+
+ public function get_wp_int_awb( $context = 'view' ) {
+ return $this->get_prop( 'wp_int_awb', $context );
+ }
+
+ public function get_wp_int_barcode( $context = 'view' ) {
+ return $this->get_prop( 'wp_int_barcode', $context );
+ }
+
+ public function get_services( $context = 'view' ) {
+ if ( $this->legacy ) {
+ return $this->get_additional_services( $context );
+ }
+
+ return parent::get_services( $context );
+ }
+
+ public function set_services( $services ) {
+ if ( $this->legacy ) {
+ $this->set_additional_services( $services );
+ } else {
+ parent::set_services( $services );
+ }
+ }
+
+ public function get_additional_services( $context = 'view' ) {
+ if ( $this->legacy ) {
+ return $this->get_prop( 'additional_services', $context );
+ } else {
+ return $this->get_services( $context );
+ }
+ }
+
+ public function set_additional_services( $value ) {
+ if ( $this->legacy ) {
+ $this->set_prop( 'additional_services', (array) $value );
+ } else {
+ $this->set_services( $value );
+ }
+ }
+
+ public function set_page_format( $value ) {
+ $this->set_prop( 'page_format', $value );
+ }
+
+ public function set_wp_int_awb( $value ) {
+ $this->set_prop( 'wp_int_awb', $value );
+ }
+
+ public function set_wp_int_barcode( $value ) {
+ $this->set_prop( 'wp_int_barcode', $value );
+ }
+
+ public function get_stamp_total( $context = 'view' ) {
+ return $this->get_prop( 'stamp_total', $context );
+ }
+
+ public function set_stamp_total( $value ) {
+ $this->set_prop( 'stamp_total', absint( $value ) );
+ }
+
+ public function get_shop_order_id( $context = 'view' ) {
+ return $this->get_prop( 'shop_order_id', $context );
+ }
+
+ public function set_shop_order_id( $value ) {
+ $this->set_prop( 'shop_order_id', $value );
+ }
+
+ public function get_voucher_id( $context = 'view' ) {
+ return $this->get_prop( 'voucher_id', $context );
+ }
+
+ public function set_voucher_id( $value ) {
+ $this->set_prop( 'voucher_id', $value );
+ }
+
+ public function get_original_url( $context = 'view' ) {
+ return $this->get_prop( 'original_url', $context );
+ }
+
+ public function set_original_url( $value ) {
+ $this->set_prop( 'original_url', $value );
+ }
+
+ public function get_manifest_url( $context = 'view' ) {
+ return $this->get_prop( 'manifest_url', $context );
+ }
+
+ public function set_manifest_url( $value ) {
+ $this->set_prop( 'manifest_url', $value );
+ }
+
+ public function is_warenpost_international() {
+ if ( ! empty( $this->get_wp_int_awb() ) ) {
+ return true;
+ } elseif ( $api = Package::get_internetmarke_api() ) {
+ return $api->is_warenpost_international( $this->get_product_id() );
+ }
+
+ return false;
+ }
+
+ public function is_trackable() {
+ $voucher_id = $this->get_voucher_id();
+ $is_trackable = false;
+
+ if ( ! empty( $voucher_id ) && $voucher_id !== $this->get_number() ) {
+ $is_trackable = true;
+ } elseif ( in_array( $this->get_product_id(), [ 195, 196, 197, 198, 199, 200, 1007, 1017, 1027, 1037, 1047, 1057 ] ) ) {
+ $is_trackable = true;
+ } elseif( ! empty( $this->get_wp_int_barcode() ) && in_array( 'TRCK', $this->get_services() ) ) {
+ $is_trackable = true;
+ }
+
+ return apply_filters( "{$this->get_general_hook_prefix()}is_trackable", $is_trackable, $this );
+ }
+
+ /**
+ * @return \WP_Error|true
+ */
+ public function fetch() {
+ $result = new \WP_Error();
+
+ try {
+ Package::get_internetmarke_api()->get_label( $this );
+ } catch( \Exception $e ) {
+ $result->add( 'deutsche-post-api-error', $e->getMessage() );
+ }
+
+ if ( wc_gzd_dhl_wp_error_has_errors( $result ) ) {
+ return $result;
+ } else {
+ return true;
+ }
+ }
+
+ public function delete( $force_delete = false ) {
+ if ( $api = Package::get_internetmarke_api() ) {
+ try {
+ $api->delete_label( $this );
+ } catch( \Exception $e ) {}
+ }
+
+ return parent::delete( $force_delete );
+ }
+}
diff --git a/packages/woocommerce-germanized-dhl/src/Label/DeutschePostReturn.php b/packages/woocommerce-germanized-dhl/src/Label/DeutschePostReturn.php
new file mode 100644
index 000000000..2b346bdc7
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/Label/DeutschePostReturn.php
@@ -0,0 +1,35 @@
+ '',
+ 'shop_order_id' => '',
+ 'stamp_total' => 0,
+ 'voucher_id' => '',
+ 'original_url' => '',
+ 'manifest_url' => '',
+ 'sender_address' => array()
+ );
+
+ protected function get_hook_prefix() {
+ return 'woocommerce_gzd_deutsche_post_return_label_get_';
+ }
+
+ public function get_type() {
+ return 'return';
+ }
+}
diff --git a/packages/woocommerce-germanized-dhl/src/Label/Label.php b/packages/woocommerce-germanized-dhl/src/Label/Label.php
new file mode 100644
index 000000000..8eab38f9e
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/Label/Label.php
@@ -0,0 +1,171 @@
+legacy = $legacy;
+
+ if ( $this->legacy ) {
+ $this->data['dhl_product'] = '';
+ $this->data['default_path'] = '';
+ $this->data['export_path'] = '';
+ $this->data['preferred_time_start'] = '';
+ $this->data['preferred_time_end'] = '';
+ }
+
+ if ( $data instanceof Label ) {
+ $label_id = $data->get_id();
+ } elseif ( is_numeric( $data ) ) {
+ $label_id = $data;
+ }
+
+ parent::__construct( $data );
+
+ /**
+ * Legacy object support
+ */
+ if ( $this->legacy && $this->get_id() <= 0 and $label_id > 0 ) {
+ $data_store = WC_Data_Store::load( 'dhl-legacy-label' );
+
+ // If we have an ID, load the user from the DB.
+ try {
+ $this->set_id( $label_id );
+ $data_store->read( $this );
+
+ $this->data_store_name = 'dhl-legacy-label';
+ $this->data_store = $data_store;
+ $this->object_type = 'dhl_label';
+ $this->cache_group = 'dhl-labels';
+ } catch ( Exception $e ) {
+ $this->set_id( 0 );
+ $this->set_object_read( true );
+ }
+ }
+ }
+
+ public function get_dhl_product( $context = 'view' ) {
+ return $this->get_product_id( $context );
+ }
+
+ /**
+ * Returns linked children labels.
+ *
+ * @return ShipmentLabel[]
+ */
+ public function get_children() {
+ if ( ! $this->legacy ) {
+ return parent::get_children();
+ } else {
+ return wc_gzd_dhl_get_labels( array(
+ 'parent_id' => $this->get_id(),
+ ) );
+ }
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | Setters
+ |--------------------------------------------------------------------------
+ */
+ protected function set_time_prop( $prop, $value ) {
+ try {
+
+ if ( empty( $value ) ) {
+ $this->set_prop( $prop, null );
+ return;
+ }
+
+ if ( is_a( $value, 'WC_DateTime' ) ) {
+ $datetime = $value;
+ } elseif ( is_numeric( $value ) ) {
+ $datetime = new WC_DateTime( "@{$value}" );
+ } else {
+ $timestamp = wc_string_to_timestamp( $value );
+ $datetime = new WC_DateTime( "@{$timestamp}" );
+ }
+
+ $this->set_prop( $prop, $datetime );
+ } catch ( Exception $e ) {} // @codingStandardsIgnoreLine.
+ }
+
+ public function is_legacy() {
+ return $this->legacy;
+ }
+
+ public function get_product_id( $context = 'view' ) {
+ if ( $this->legacy ) {
+ return $this->get_prop( 'dhl_product', $context );
+ }
+
+ return parent::get_product_id();
+ }
+
+ public function get_preferred_time() {
+ $start = $this->get_preferred_time_start();
+ $end = $this->get_preferred_time_end();
+
+ if ( $start && $end ) {
+ return $start->date( 'H:i' ) . '-' . $end->date( 'H:i' );
+ }
+
+ return null;
+ }
+
+ public function get_preferred_time_start( $context = 'view' ) {
+ return $this->get_prop( 'preferred_time_start', $context );
+ }
+
+ public function get_preferred_time_end( $context = 'view' ) {
+ return $this->get_prop( 'preferred_time_end', $context );
+ }
+
+ public function get_preferred_formatted_time() {
+ $start = $this->get_preferred_time_start();
+ $end = $this->get_preferred_time_end();
+
+ if ( $start && $end ) {
+ return sprintf( _x( '%s-%s', 'dhl time-span', 'woocommerce-germanized' ), $start->date( 'H' ), $end->date( 'H' ) );
+ }
+
+ return null;
+ }
+
+ public function set_preferred_time_start( $time ) {
+ $this->set_time_prop( 'preferred_time_start', $time );
+ }
+
+ public function set_preferred_time_end( $time ) {
+ $this->set_time_prop( 'preferred_time_end', $time );
+ }
+
+ protected function get_file_by_path( $file ) {
+ if ( $this->legacy ) {
+ // 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;
+ }
+ } else {
+ return parent::get_file_by_path( $file );
+ }
+ }
+}
diff --git a/packages/woocommerce-germanized-dhl/src/Label/ReturnLabel.php b/packages/woocommerce-germanized-dhl/src/Label/ReturnLabel.php
new file mode 100644
index 000000000..f984dd94d
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/Label/ReturnLabel.php
@@ -0,0 +1,88 @@
+legacy = $legacy;
+
+ if ( $this->legacy ) {
+ $this->data['dhl_product'] = '';
+ }
+
+ if ( $data instanceof Label ) {
+ $label_id = $data->get_id();
+ } elseif ( is_numeric( $data ) ) {
+ $label_id = $data;
+ }
+
+ parent::__construct( $data );
+
+ /**
+ * Legacy object support
+ */
+ if ( $this->legacy && $this->get_id() <= 0 and $label_id > 0 ) {
+ $data_store = WC_Data_Store::load( 'dhl-legacy-label' );
+
+ // If we have an ID, load the user from the DB.
+ try {
+ $this->set_id( $label_id );
+ $data_store->read( $this );
+
+ $this->data_store_name = 'dhl-legacy-label';
+ $this->data_store = $data_store;
+ $this->object_type = 'dhl_label';
+ $this->cache_group = 'dhl-labels';
+ } catch ( Exception $e ) {
+ $this->set_id( 0 );
+ $this->set_object_read( true );
+ }
+ }
+ }
+
+ public function is_legacy() {
+ return $this->legacy;
+ }
+
+ public function get_product_id( $context = 'view' ) {
+ if ( $this->legacy ) {
+ return $this->get_prop( 'dhl_product', $context );
+ }
+
+ return parent::get_product_id();
+ }
+
+ public function get_dhl_product( $context = 'view' ) {
+ return $this->get_product_id( $context );
+ }
+
+ protected function get_file_by_path( $file ) {
+ if ( $this->legacy ) {
+ // 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;
+ }
+ } else {
+ return parent::get_file_by_path( $file );
+ }
+ }
+}
diff --git a/packages/woocommerce-germanized-dhl/src/Legacy/DataStores/Label.php b/packages/woocommerce-germanized-dhl/src/Legacy/DataStores/Label.php
new file mode 100644
index 000000000..83f7c4457
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/Legacy/DataStores/Label.php
@@ -0,0 +1,570 @@
+set_date_created( current_time( 'timestamp', true ) );
+
+ $data = array(
+ 'label_number' => $label->get_number(),
+ 'label_shipment_id' => $label->get_shipment_id(),
+ 'label_path' => $label->get_path(),
+ 'label_default_path' => $label->get_default_path(),
+ 'label_export_path' => $label->get_export_path(),
+ 'label_dhl_product' => $label->get_dhl_product(),
+ 'label_type' => $label->get_type(),
+ 'label_parent_id' => is_callable( array( $label, 'get_parent_id' ) ) ? $label->get_parent_id() : 0,
+ '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_dhl_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_dhl_{$hook_postfix}label_created", $label_id, $label );
+ }
+ }
+
+ protected function get_hook_postfix( $label ) {
+ if ( 'simple' !== $label->get_type() ) {
+ return $label->get_type() . '_';
+ }
+
+ return '';
+ }
+
+ /**
+ * Method to update a label in the database.
+ *
+ * @param \Vendidero\Germanized\DHL\Legacy\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_dhl_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_dhl_{$hook_postfix}label_updated", $label->get_id(), $label, $changed_props );
+ }
+
+ /**
+ * Remove a shipment from the database.
+ *
+ * @since 3.0.0
+ * @param \Vendidero\Germanized\DHL\Legacy\Label $label Label object.
+ * @param bool $force_delete Unused param.
+ */
+ public function delete( &$label, $force_delete = false ) {
+ global $wpdb;
+
+ // Delete files
+ if ( $file = $label->get_file() ) {
+ wp_delete_file( $file );
+ }
+
+ if ( $file_default = $label->get_default_file() ) {
+ wp_delete_file( $file_default );
+ }
+
+ if ( $file_export = $label->get_export_file() ) {
+ wp_delete_file( $file_export );
+ }
+
+ $wpdb->delete( $wpdb->gzd_dhl_labels, array( 'label_id' => $label->get_id() ), array( '%d' ) );
+ $wpdb->delete( $wpdb->gzd_dhl_labelmeta, array( 'gzd_dhl_label_id' => $label->get_id() ), array( '%d' ) );
+
+ $this->clear_caches( $label );
+
+ if ( 'simple' === $label->get_type() ) {
+
+ if ( $return = $label->get_inlay_return_label() ) {
+ $return->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\Legacy\Label $label The label object.
+ *
+ * @since 3.0.0
+ * @package Vendidero/Germanized/DHL
+ */
+ do_action( "woocommerce_gzd_dhl_{$hook_postfix}label_deleted", $label->get_id(), $label );
+ }
+
+ /**
+ * Read a shipment from the database.
+ *
+ * @since 3.0.0
+ *
+ * @param \Vendidero\Germanized\DHL\Legacy\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_dhl_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,
+ 'default_path' => $data->label_default_path,
+ 'export_path' => $data->label_export_path,
+ 'dhl_product' => $data->label_dhl_product,
+ 'date_created' => 0 < $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\DHL\Legacy\Label $label The label object.
+ *
+ * @since 3.0.0
+ * @package Vendidero/Germanized/DHL
+ */
+ do_action( "woocommerce_gzd_dhl_{$hook_postfix}label_loaded", $label );
+ } else {
+ throw new Exception( _x( 'Invalid label.', 'dhl', 'woocommerce-germanized' ) );
+ }
+ }
+
+ /**
+ * Clear any caches.
+ *
+ * @param \Vendidero\Germanized\DHL\Legacy\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 string
+ */
+ public function get_label_type( $label_id ) {
+ global $wpdb;
+
+ $type = $wpdb->get_col(
+ $wpdb->prepare(
+ "SELECT label_type FROM {$wpdb->gzd_dhl_labels} WHERE label_id = %d LIMIT 1",
+ $label_id
+ )
+ );
+
+ return ! empty( $type ) ? $type[0] : false;
+ }
+
+ /**
+ * Read extra data associated with the shipment.
+ *
+ * @param \Vendidero\Germanized\DHL\Legacy\Label $label Label object.
+ * @since 3.0.0
+ */
+ protected function read_label_data( &$label ) {
+ $props = array();
+
+ foreach( $this->internal_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 );
+ }
+
+ 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 ) ) {
+ continue;
+ }
+
+ $meta_key_to_props[ $meta_key ] = $prop_name;
+ }
+
+ $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;
+
+ switch ( $prop ) {
+ case "preferred_day":
+ case "ident_date_of_birth":
+ $value = $value ? strtotime( date("Y-m-d", $value->getOffsetTimestamp() ) ) : '';
+ break;
+ case "preferred_time_start":
+ case "preferred_time_end":
+ $value = $value ? strtotime( date("H:i:s", $value->getOffsetTimestamp() ) ) : '';
+ break;
+ case "email_notification":
+ case "has_inlay_return":
+ case "codeable_address_only":
+ case "cod_includes_additional_total":
+ $value = wc_bool_to_string( $value );
+ break;
+ }
+
+ $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\DHL\Legacy\Label $label The label object.
+ * @param array $updated_props The updated properties.
+ *
+ * @since 3.0.0
+ * @package Vendidero/Germanized/DHL
+ */
+ do_action( 'woocommerce_gzd_dhl_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();
+ }
+
+ // 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_dhl_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_dhl_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_dhl_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_dhl_labels}" ) );
+ }
+}
diff --git a/packages/woocommerce-germanized-dhl/src/Legacy/DownloadHandler.php b/packages/woocommerce-germanized-dhl/src/Legacy/DownloadHandler.php
new file mode 100644
index 000000000..1108bac6c
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/Legacy/DownloadHandler.php
@@ -0,0 +1,78 @@
+ false,
+ 'file_type' => '',
+ 'check_permissions' => true,
+ ) );
+
+ $args['force'] = wc_string_to_bool( $args['force'] );
+
+ return $args;
+ }
+
+ public static function download_label( $label_id, $args = array() ) {
+ $args = self::parse_args( $args );
+ $has_permission = current_user_can( 'edit_shop_orders' );
+
+ if ( ! $args['check_permissions'] ) {
+ $has_permission = true;
+ }
+
+ if ( $has_permission ) {
+ if ( $label = wc_gzd_get_shipment_label( $label_id ) ) {
+ $file = $label->get_file( $args['file_type'] );
+ $filename = $label->get_filename( $args['file_type'] );
+
+ if ( file_exists( $file ) ) {
+ if ( $args['force'] ) {
+ WC_Download_Handler::download_file_force( $file, $filename );
+ } else {
+ self::embed( $file, $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 Generic.PHP.NoSilencedErrors.Discouraged
+ }
+ } else {
+ @ob_end_clean(); // phpcs:ignore Generic.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 Generic.PHP.NoSilencedErrors.Discouraged
+
+ if ( ! $file_size ) {
+ return;
+ }
+
+ header( 'Content-Length: ' . $file_size );
+
+ @readfile( $file_path );
+ exit();
+ }
+}
diff --git a/packages/woocommerce-germanized-dhl/src/Legacy/LabelFactory.php b/packages/woocommerce-germanized-dhl/src/Legacy/LabelFactory.php
new file mode 100644
index 000000000..04ed11660
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/Legacy/LabelFactory.php
@@ -0,0 +1,29 @@
+ 10,
+ 'shipment_id' => '',
+ 'parent_id' => '',
+ 'type' => wc_gzd_legacy_dhl_get_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_dhl_label_query_args', $this->get_query_vars() );
+ $args = WC_Data_Store::load( 'dhl-legacy-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_dhl_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 );
+ } else {
+ $this->results = $wpdb->get_col( $this->request );
+ }
+
+ if ( isset( $qv['count_total'] ) && $qv['count_total'] ) {
+ $found_labels_query = 'SELECT FOUND_ROWS()';
+ $this->total_labels = (int) $wpdb->get_var( $found_labels_query );
+ }
+ }
+
+ if ( ! $this->results ) {
+ return;
+ }
+
+ if ( 'objects' == $qv['fields'] ) {
+ foreach ( $this->results as $key => $label ) {
+ $this->results[ $key ] = wc_gzd_dhl_get_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['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_dhl_labels.$field";
+ }
+
+ $this->query_fields = implode( ',', $this->query_fields );
+
+ } elseif ( 'objects' == $this->args['fields'] ) {
+ $this->query_fields = "$wpdb->gzd_dhl_labels.*";
+ } else {
+ $this->query_fields = "$wpdb->gzd_dhl_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_dhl_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'] );
+ }
+
+ // 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' ) );
+ }
+
+ 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' );
+ }
+ }
+
+ /**
+ * 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'.
+ *
+ * @param string[] $search_columns Array of column names to be searched.
+ * @param string $search Text being searched.
+ * @param LegacyLabelQuery $this The current LabelQuery instance.
+ *
+ * @since 3.0.0
+ *
+ * @package Vendidero/Germanized/DHL
+ */
+ $search_columns = apply_filters( 'woocommerce_gzd_dhl_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_dhl_label', $wpdb->gzd_dhl_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_dhl_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_dhl_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 );
+ } else {
+ $searches[] = $wpdb->prepare( "$col LIKE %s", $like );
+ }
+ }
+
+ 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' ) ) ) {
+ $_orderby = 'label_' . $orderby;
+ } elseif ( 'ID' == $orderby || 'id' == $orderby ) {
+ $_orderby = 'label_id';
+ } elseif ( 'meta_value' == $orderby || $this->get( 'meta_key' ) == $orderby ) {
+ $_orderby = "$wpdb->gzd_dhl_labelmeta.meta_value";
+ } elseif ( 'meta_value_num' == $orderby ) {
+ $_orderby = "$wpdb->gzd_dhl_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_dhl_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-dhl/src/Order.php b/packages/woocommerce-germanized-dhl/src/Order.php
new file mode 100644
index 000000000..e9b50b01f
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/Order.php
@@ -0,0 +1,385 @@
+order = $order;
+ }
+
+ /**
+ * Returns the Woo WC_Order original object
+ *
+ * @return object|WC_Order
+ */
+ public function get_order() {
+ return $this->order;
+ }
+
+ protected function get_dhl_props() {
+ $data = (array) $this->get_order()->get_meta( '_dhl_services' );
+
+ return $data;
+ }
+
+ protected function set_dhl_date_prop( $prop, $value, $format = 'Y-m-d' ) {
+ try {
+ if ( ! empty( $value ) ) {
+
+ if ( is_a( $value, 'WC_DateTime' ) ) {
+ $datetime = $value;
+ } elseif ( is_numeric( $value ) ) {
+ $datetime = new WC_DateTime( "@{$value}" );
+ } else {
+ $timestamp = wc_string_to_timestamp( $value );
+ $datetime = new WC_DateTime( "@{$timestamp}" );
+ }
+
+ if ( $datetime ) {
+ $value = strtotime( date( $format, $datetime->getOffsetTimestamp() ) );
+ }
+ }
+ } catch ( Exception $e ) {} // @codingStandardsIgnoreLine.
+
+ $this->set_dhl_prop( $prop, $value );
+ }
+
+ protected function set_dhl_time_prop( $prop, $value ) {
+ $this->set_dhl_date_prop( $prop, $value, 'H:i:s' );
+ }
+
+ protected function set_dhl_boolean_prop( $prop, $value ) {
+ $value = wc_bool_to_string( $value );
+ $this->set_dhl_prop( $prop, $value );
+ }
+
+ protected function set_dhl_prop( $prop, $value ) {
+ $data = $this->get_dhl_props();
+
+ if ( empty( $value ) ) {
+ $this->delete_dhl_prop( $prop );
+ } else {
+ $data[ $prop ] = $value;
+ $this->get_order()->update_meta_data( '_dhl_services', $data );
+ }
+ }
+
+ protected function delete_dhl_prop( $prop ) {
+ $data = $this->get_dhl_props();
+
+ if ( array_key_exists( $prop, $data ) ) {
+ unset( $data[ $prop ] );
+ }
+
+ $this->get_order()->update_meta_data( '_dhl_services', $data );
+ }
+
+ protected function get_dhl_prop( $prop ) {
+ $data = $this->get_dhl_props();
+ $prop_data = array_key_exists( $prop, $data ) ? $data[ $prop ] : null;
+
+ // Legacy DHL plugin support
+ if ( is_null( $prop_data ) ) {
+ $meta = $this->get_order()->get_meta( '_pr_shipment_dhl_label_items' );
+
+ if ( ! empty( $meta ) ) {
+
+ if ( 'preferred_day' === $prop ) {
+ $preferred_day = isset( $meta['pr_dhl_preferred_day'] ) ? $meta['pr_dhl_preferred_day'] : false;
+
+ if ( $preferred_day ) {
+ return strtotime( $preferred_day );
+ }
+ } elseif( 'preferred_time_start' === $prop || 'preferred_time_end' === $prop ) {
+ $preferred_time = isset( $meta['pr_dhl_preferred_time'] ) ? $meta['pr_dhl_preferred_time'] : false;
+
+ if ( $preferred_time ) {
+ $preferred_time_start_part = substr( $preferred_time, 0, 4 );
+ $preferred_time_start = implode( ':', str_split( $preferred_time_start_part, 2 ) );
+
+ $preferred_time_end_part = substr( $preferred_time, 4, 8 );
+ $preferred_time_end = implode( ':', str_split( $preferred_time_end_part, 2 ) );
+
+ if ( 'preferred_time_start' === $prop ) {
+ return strtotime( $preferred_time_start );
+ } elseif( 'preferred_time_end' === $prop ) {
+ return strtotime( $preferred_time_end );
+ }
+ }
+ } elseif( 'preferred_neighbor' === $prop ) {
+ $has_neighbor = ( isset( $meta['pr_dhl_preferred_location_neighbor'] ) && 'preferred_neighbor' === $meta['pr_dhl_preferred_location_neighbor'] ) ? true : false;
+
+ if ( $has_neighbor ) {
+ return ( isset( $meta['pr_dhl_preferred_neighbour_name'] ) ? $meta['pr_dhl_preferred_neighbour_name'] : '' );
+ }
+ } elseif( 'preferred_neighbor_address' === $prop ) {
+ $has_neighbor = ( isset( $meta['pr_dhl_preferred_location_neighbor'] ) && 'preferred_neighbor' === $meta['pr_dhl_preferred_location_neighbor'] ) ? true : false;
+
+ if ( $has_neighbor ) {
+ return ( isset( $meta['pr_dhl_preferred_neighbour_address'] ) ? $meta['pr_dhl_preferred_neighbour_address'] : '' );
+ }
+ } elseif( 'preferred_location' === $prop ) {
+ $has_location = ( isset( $meta['pr_dhl_preferred_location_neighbor'] ) && 'preferred_location' === $meta['pr_dhl_preferred_location_neighbor'] ) ? true : false;
+
+ if ( $has_location ) {
+ return ( isset( $meta['pr_dhl_preferred_location'] ) ? $meta['pr_dhl_preferred_location'] : '' );
+ }
+ }
+ }
+ }
+
+ return $prop_data;
+ }
+
+ /**
+ * @return bool
+ */
+ public function supports_email_notification() {
+ $has_email_notification = wc_gzd_order_supports_parcel_delivery_reminder( $this->get_order() );
+
+ /**
+ * Allow global setting to override email notification support.
+ */
+ if ( false === $has_email_notification && 'yes' === Package::get_setting( 'label_force_email_transfer' ) ) {
+ $has_email_notification = true;
+ }
+
+ /**
+ * Filter to adjust whether customer data (email address) should be handed over to DHL to provide
+ * with services such as email notification or parcel outlet routing. By default this may only work
+ * if the customer has opted-in via checkbox during checkout.
+ *
+ * @param boolean $has_email_notification Whether the order supports email notification (handing over customer data to DHL).
+ * @param Order $order The order instance.
+ *
+ * @since 3.1.6
+ * @package Vendidero/Germanized/DHL
+ */
+ return apply_filters( 'woocommerce_gzd_dhl_order_supports_email_notification', $has_email_notification, $this );
+ }
+
+ public function get_min_age() {
+ $min_age = wc_gzd_get_order_min_age( $this->get_order() );
+ $ages = wc_gzd_dhl_get_visual_min_ages();
+
+ if ( empty( $min_age ) || ! array_key_exists( 'A' . $min_age, $ages ) ) {
+ $min_age = '';
+ } else {
+ $min_age = 'A' . $min_age;
+ }
+
+ return $min_age;
+ }
+
+ public function needs_age_verification() {
+ $min_age = $this->get_min_age();
+ $needs_verification = false;
+
+ if ( ! empty( $min_age ) ) {
+ $needs_verification = true;
+ }
+
+ /**
+ * Filter to decide whether a DHL order needs age verification or not.
+ *
+ * @param boolean $needs_verification Whether the order needs age verification or not.
+ * @param Order $order The order instance.
+ *
+ * @since 3.0.0
+ * @package Vendidero/Germanized/DHL
+ */
+ return apply_filters( 'woocommerce_gzd_dhl_order_needs_age_verificaton', $needs_verification, $this );
+ }
+
+ public function has_cod_payment() {
+ $result = false;
+
+ if ( 'cod' === $this->get_order()->get_payment_method() ) {
+ $result = true;
+ }
+
+ /**
+ * Filter to decide whether a DHL order has cash on delivery payment enabled.
+ *
+ * @param boolean $result Whether the order has COD payment or not.
+ * @param Order $order The order instance.
+ *
+ * @since 3.0.0
+ * @package Vendidero/Germanized/DHL
+ */
+ return apply_filters( 'woocommerce_gzd_dhl_order_has_cod_payment', $result, $this );
+ }
+
+ public function get_date_of_birth() {
+ if ( $timestamp = $this->get_dhl_prop( 'date_of_birth' ) ) {
+ $date = new WC_DateTime( "@{$timestamp}" );
+ return $date;
+ }
+
+ return null;
+ }
+
+ public function get_preferred_day() {
+ if ( $timestamp = $this->get_dhl_prop( 'preferred_day' ) ) {
+ $date = new \WC_DateTime();
+ $date->setTimestamp( $timestamp );
+ $date->setTimezone( new \DateTimeZone( 'Europe/Berlin' ) );
+
+ return $date;
+ }
+
+ return null;
+ }
+
+ public function has_preferred_day() {
+ return $this->get_preferred_day() !== null;
+ }
+
+ public function get_preferred_time_start() {
+ if ( $timestamp = $this->get_dhl_prop( 'preferred_time_start' ) ) {
+ $date = new \WC_DateTime();
+ $date->setTimestamp( $timestamp );
+ $date->setTimezone( new \DateTimeZone( 'Europe/Berlin' ) );
+
+ return $date;
+ }
+
+ return null;
+ }
+
+ public function get_preferred_time_end() {
+ if ( $timestamp = $this->get_dhl_prop( 'preferred_time_end' ) ) {
+ $date = new \WC_DateTime();
+ $date->setTimestamp( $timestamp );
+ $date->setTimezone( new \DateTimeZone( 'Europe/Berlin' ) );
+
+ return $date;
+ }
+
+ return null;
+ }
+
+ public function has_preferred_time() {
+ return $this->get_preferred_time_start() !== null && $this->get_preferred_time_end() !== null;
+ }
+
+ public function get_preferred_time() {
+ $start = $this->get_preferred_time_start();
+ $end = $this->get_preferred_time_end();
+
+ if ( $start && $end ) {
+ return $start->date( 'H:i' ) . '-' . $end->date( 'H:i' );
+ }
+
+ return null;
+ }
+
+ public function get_preferred_formatted_time() {
+ $start = $this->get_preferred_time_start();
+ $end = $this->get_preferred_time_end();
+
+ if ( $start && $end ) {
+ return sprintf( _x( '%s-%s', 'dhl time-span', 'woocommerce-germanized' ), $start->date( 'H' ), $end->date( 'H' ) );
+ }
+
+ return null;
+ }
+
+ public function get_preferred_location() {
+ return $this->get_dhl_prop( 'preferred_location' );
+ }
+
+ public function has_preferred_location() {
+ $location = $this->get_preferred_location();
+
+ return ! empty( $location ) ? true : false;
+ }
+
+ public function get_preferred_neighbor() {
+ return $this->get_dhl_prop( 'preferred_neighbor' );
+ }
+
+ public function get_preferred_neighbor_address() {
+ return $this->get_dhl_prop( 'preferred_neighbor_address' );
+ }
+
+ public function has_preferred_neighbor() {
+ $address = $this->get_preferred_neighbor_formatted_address();
+
+ return ! empty( $address ) ? true : false;
+ }
+
+ public function get_preferred_neighbor_formatted_address() {
+
+ if ( ! empty( $this->get_preferred_neighbor() ) && ! empty( $this->get_preferred_neighbor_address() ) ) {
+ return $this->get_preferred_neighbor() . ', ' . $this->get_preferred_neighbor_address();
+ }
+
+ return '';
+ }
+
+ public function set_preferred_day( $date ) {
+ $this->set_dhl_date_prop( 'preferred_day', $date );
+ }
+
+ public function set_preferred_time_start( $time ) {
+ $this->set_dhl_time_prop( 'preferred_time_start', $time );
+ }
+
+ public function set_preferred_time_end( $time ) {
+ $this->set_dhl_time_prop( 'preferred_time_end', $time );
+ }
+
+ public function set_preferred_location( $location ) {
+ $this->set_dhl_prop( 'preferred_location', $location );
+ }
+
+ public function set_preferred_neighbor( $neighbor ) {
+ $this->set_dhl_prop( 'preferred_neighbor', $neighbor );
+ }
+
+ public function set_preferred_neighbor_address( $address ) {
+ $this->set_dhl_prop( 'preferred_neighbor_address', $address );
+ }
+
+ /**
+ * 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-dhl/src/Package.php b/packages/woocommerce-germanized-dhl/src/Package.php
new file mode 100644
index 000000000..633c0779e
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/Package.php
@@ -0,0 +1,1085 @@
+
+
+
SOAPClient is required. Please contact your host and make sure that SOAPClient is installed .', 'dhl', 'woocommerce-germanize-dhl' ), 'https://www.php.net/manual/class.soapclient.php', admin_url( 'admin.php?page=wc-status' ) ); ?>
+
+ format( $format );
+
+ return $date_formatted;
+ } catch( Exception $e ) {
+ return date( $format );
+ }
+ }
+
+ public static function get_holidays( $country = 'DE' ) {
+ if ( empty( self::$holidays ) ) {
+ self::$holidays = include self::get_path() . '/i18n/holidays.php';
+ }
+
+ $holidays = self::$holidays;
+
+ if ( ! empty( $country ) ) {
+ $holidays = array_key_exists( $country, self::$holidays ) ? self::$holidays[ $country ] : array();
+ }
+
+ /**
+ * Filter to adjust dates regarded as holidays for a certain country.
+ *
+ * @param array $holidays Array containing dates in Y-m-d format.
+ * @param string $country The country as ISO code.
+ *
+ * @since 3.0.0
+ * @package Vendidero/Germanized/DHL
+ */
+ return apply_filters( 'woocommerce_gzd_dhl_holidays', $holidays, $country );
+ }
+
+ /**
+ * Register custom tables within $wpdb object.
+ */
+ private static function define_tables() {
+ global $wpdb;
+
+ // List of tables without prefixes.
+ $tables = array(
+ 'gzd_dhl_labelmeta' => 'woocommerce_gzd_dhl_labelmeta',
+ 'gzd_dhl_labels' => 'woocommerce_gzd_dhl_labels',
+ 'gzd_dhl_im_products' => 'woocommerce_gzd_dhl_im_products',
+ 'gzd_dhl_im_product_services' => 'woocommerce_gzd_dhl_im_product_services',
+ );
+
+ foreach ( $tables as $name => $table ) {
+ $wpdb->$name = $wpdb->prefix . $table;
+ $wpdb->tables[] = $table;
+ }
+ }
+
+ public static function maybe_set_upload_dir() {
+ // Create a dir suffix
+ if ( ! get_option( 'woocommerce_gzd_dhl_upload_dir_suffix', false ) ) {
+ self::$upload_dir_suffix = substr( self::generate_key(), 0, 10 );
+ update_option( 'woocommerce_gzd_dhl_upload_dir_suffix', self::$upload_dir_suffix );
+ } else {
+ self::$upload_dir_suffix = get_option( 'woocommerce_gzd_dhl_upload_dir_suffix' );
+ }
+ }
+
+ public static function is_enabled() {
+ return ( self::is_dhl_enabled() || self::is_deutsche_post_enabled() );
+ }
+
+ public static function is_dhl_enabled() {
+ $is_enabled = false;
+
+ if ( $provider = self::get_dhl_shipping_provider() ) {
+ $is_enabled = $provider->is_activated();
+ }
+
+ return $is_enabled;
+ }
+
+ public static function get_country_iso_alpha3( $country_code ) {
+ if ( empty( self::$iso ) ) {
+ self::$iso = include self::get_path() . '/i18n/iso.php';
+ }
+
+ $iso = self::$iso;
+
+ if ( isset( $iso[ $country_code ] ) ) {
+ return $iso[ $country_code ];
+ }
+
+ return $country_code;
+ }
+
+ private static function includes() {
+ include_once self::get_path() . '/includes/wc-gzd-dhl-core-functions.php';
+ include_once self::get_path() . '/includes/wc-gzd-dhl-legacy-functions.php';
+
+ if ( self::is_enabled() ) {
+ if ( is_admin() ) {
+ Admin\Admin::init();
+ }
+
+ if ( ParcelLocator::is_enabled() ) {
+ ParcelLocator::init();
+ }
+
+ /**
+ * Additional services are only available for DHL products
+ */
+ if ( self::is_dhl_enabled() && ParcelServices::is_enabled() ) {
+ ParcelServices::init();
+ }
+
+ Ajax::init();
+ }
+ }
+
+ public static function init_hooks() {
+ // Filter templates
+ add_filter( 'woocommerce_gzd_default_plugin_template', array( __CLASS__, 'filter_templates' ), 10, 3 );
+
+ // Register additional label types
+ add_filter( 'woocommerce_gzd_shipment_label_types', array( __CLASS__, 'register_label_types' ), 10 );
+
+ // Sync shipment items
+ add_action( 'woocommerce_gzd_shipment_item_synced', array( __CLASS__, 'sync_item_meta' ), 10, 3 );
+ }
+
+ /**
+ * @param ShipmentItem $item
+ * @param \WC_Order_Item $order_item
+ * @param $args
+ */
+ public static function sync_item_meta( $item, $order_item, $args ) {
+ if ( $product = $item->get_product() ) {
+ $dhl_product = wc_gzd_dhl_get_product( $product );
+
+ $item->update_meta_data( '_dhl_hs_code', $dhl_product->get_hs_code() );
+ $item->update_meta_data( '_dhl_manufacture_country', $dhl_product->get_manufacture_country() );
+ }
+ }
+
+ public static function register_label_types( $types ) {
+ $types[] = 'inlay_return';
+
+ return $types;
+ }
+
+ 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;
+ }
+
+ public static function get_default_bank_account_data( $data_key = '' ) {
+ $bacs = get_option( 'woocommerce_bacs_accounts' );
+
+ if ( ! empty( $bacs ) && is_array( $bacs ) ) {
+ $data = $bacs[0];
+
+ if ( isset( $data[ 'account_' . $data_key ] ) ) {
+ return $data[ 'account_' . $data_key ];
+ } elseif ( isset( $data[ $data_key ] ) ) {
+ return $data[ $data_key ];
+ }
+ }
+
+ return '';
+ }
+
+ /**
+ * @return false|DHL
+ */
+ public static function get_dhl_shipping_provider() {
+ $provider = wc_gzd_get_shipping_provider( 'dhl' );
+
+ if ( ! is_a( $provider, '\Vendidero\Germanized\DHL\ShippingProvider\DHL' ) ) {
+ return false;
+ }
+
+ return $provider;
+ }
+
+ /**
+ * @return false|DeutschePost
+ */
+ public static function get_deutsche_post_shipping_provider() {
+ $provider = wc_gzd_get_shipping_provider( 'deutsche_post' );
+
+ if ( ! is_a( $provider, '\Vendidero\Germanized\DHL\ShippingProvider\DeutschePost' ) ) {
+ return false;
+ }
+
+ return $provider;
+ }
+
+ public static function eur_to_cents( $price ) {
+ return round( $price * 100 );
+ }
+
+ public static function cents_to_eur( $price ) {
+ return $price > 0 ? $price / 100 : 0;
+ }
+
+ public static function add_shipping_provider_class_name( $class_names ) {
+ $class_names['dhl'] = '\Vendidero\Germanized\DHL\ShippingProvider\DHL';
+ $class_names['deutsche_post'] = '\Vendidero\Germanized\DHL\ShippingProvider\DeutschePost';
+
+ return $class_names;
+ }
+
+ public static function install() {
+ self::on_shipments_init();
+ Install::install();
+ }
+
+ public static function install_integration() {
+ self::install();
+ }
+
+ public static function is_integration() {
+ return class_exists( 'WooCommerce_Germanized' ) ? true : false;
+ }
+
+ public static function register_data_stores( $stores ) {
+ $stores['dhl-legacy-label'] = 'Vendidero\Germanized\DHL\Legacy\DataStores\Label';
+
+ return $stores;
+ }
+
+ public static function get_api() {
+ if ( is_null( self::$api ) ) {
+ self::$api = new Paket( self::get_base_country() );
+ }
+
+ return self::$api;
+ }
+
+ public static function get_internetmarke_api() {
+ if ( is_null( self::$im_api ) && self::is_deutsche_post_enabled() ) {
+ self::$im_api = new Internetmarke();
+ }
+
+ return self::$im_api;
+ }
+
+ /**
+ * 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__ );
+ }
+
+ public static function get_template_path() {
+ return 'woocommerce-germanized/';
+ }
+
+ /**
+ * 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 is_debug_mode() {
+ $is_debug_mode = ( defined( 'WC_GZD_DHL_DEBUG' ) && WC_GZD_DHL_DEBUG );
+
+ if ( ! $is_debug_mode && ( $provider = self::get_dhl_shipping_provider() ) ) {
+ $is_debug_mode = $provider->is_sandbox();
+ }
+
+ return $is_debug_mode;
+ }
+
+ public static function enable_logging() {
+ return ( defined( 'WC_GZD_DHL_LOG_ENABLE' ) && WC_GZD_DHL_LOG_ENABLE ) || self::is_debug_mode();
+ }
+
+ private static function define_constant( $name, $value ) {
+ if ( ! defined( $name ) ) {
+ define( $name, $value );
+ }
+ }
+
+ public static function get_app_id() {
+ return 'woo_germanized_2';
+ }
+
+ public static function get_app_token() {
+ return '8KdXFjxwY0I1oOEo28Jk997tS5Rkky';
+ }
+
+ public static function get_geschaeftskunden_portal_url() {
+ return 'https://www.dhl-geschaeftskundenportal.de';
+ }
+
+ public static function get_internetmarke_main_url() {
+ return 'https://internetmarke.deutschepost.de/OneClickForAppV3?wsdl';
+ }
+
+ public static function get_warenpost_international_rest_url() {
+ return 'https://api.deutschepost.com';
+ }
+
+ public static function get_internetmarke_products_url() {
+ return 'https://prodws.deutschepost.de:8443/ProdWSProvider_1_1/prodws?wsdl';
+ }
+
+ public static function get_internetmarke_refund_url() {
+ return 'https://internetmarke.deutschepost.de/OneClickForRefund?wsdl';
+ }
+
+ public static function get_internetmarke_partner_id() {
+ return 'AVHGE';
+ }
+
+ public static function get_internetmarke_token() {
+ return 'l4e0TNkqpGKd0YIhyuz3m4vzEek1iZY4';
+ }
+
+ public static function get_internetmarke_key_phase() {
+ return 1;
+ }
+
+ public static function get_internetmarke_product_username() {
+ return 'vendidero';
+ }
+
+ public static function get_internetmarke_product_password() {
+ return 'A&5%bk?dx8';
+ }
+
+ public static function get_internetmarke_product_mandant_id() {
+ return 'VENDIDERO';
+ }
+
+ public static function is_deutsche_post_enabled() {
+ $is_enabled = false;
+
+ if ( $provider = self::get_deutsche_post_shipping_provider() ) {
+ $is_enabled = $provider->is_activated();
+ }
+
+ return $is_enabled;
+ }
+
+ public static function get_internetmarke_username() {
+ if ( self::is_debug_mode() && defined( 'WC_GZD_DHL_IM_SANDBOX_USER' ) ) {
+ return WC_GZD_DHL_IM_SANDBOX_USER;
+ } else {
+ return self::get_setting( 'deutsche_post_api_username' );
+ }
+ }
+
+ public static function get_internetmarke_warenpost_int_ekp() {
+ $ekp = self::get_setting( 'deutsche_post_warenpost_int_ekp' );
+
+ if ( empty( $ekp ) ) {
+ $ekp = '0000012207';
+ }
+
+ return $ekp;
+ }
+
+ /**
+ * The Warenpost International API (necessary for customs forms)
+ * needs separate Sandbox credentials. In live mode the Portokasse credentials are being used.
+ *
+ * @return string
+ */
+ public static function get_internetmarke_warenpost_int_username() {
+ if ( self::is_debug_mode() && defined( 'WC_GZD_DHL_IM_WP_SANDBOX_USER' ) ) {
+ return WC_GZD_DHL_IM_WP_SANDBOX_USER;
+ } else {
+ return self::get_setting( 'deutsche_post_api_username' );
+ }
+ }
+
+ public static function get_internetmarke_password() {
+ if ( self::is_debug_mode() && defined( 'WC_GZD_DHL_IM_SANDBOX_PASSWORD' ) ) {
+ return WC_GZD_DHL_IM_SANDBOX_PASSWORD;
+ } else {
+ return self::get_setting( 'deutsche_post_api_password' );
+ }
+ }
+
+ public static function get_internetmarke_warenpost_int_password() {
+ if ( self::is_debug_mode() && defined( 'WC_GZD_DHL_IM_WP_SANDBOX_PASSWORD' ) ) {
+ return WC_GZD_DHL_IM_WP_SANDBOX_PASSWORD;
+ } else {
+ return self::get_setting( 'deutsche_post_api_password' );
+ }
+ }
+
+ /**
+ * CIG Authentication (basic auth) user. In Sandbox mode use Developer ID and password of entwickler.dhl.de
+ *
+ * @return mixed|string|void
+ */
+ public static function get_cig_user() {
+ $debug_user = defined( 'WC_GZD_DHL_SANDBOX_USER' ) ? WC_GZD_DHL_SANDBOX_USER : self::get_setting( 'api_sandbox_username' );
+ $debug_user = strtolower( $debug_user );
+
+ return self::is_debug_mode() ? $debug_user : self::get_app_id();
+ }
+
+ /**
+ * CIG Authentication (basic auth) password. In Sandbox mode use Developer ID and password of entwickler.dhl.de
+ *
+ * @return mixed|string|void
+ */
+ public static function get_cig_password() {
+ $debug_pwd = defined( 'WC_GZD_DHL_SANDBOX_PASSWORD' ) ? WC_GZD_DHL_SANDBOX_PASSWORD : self::get_setting( 'api_sandbox_password' );
+
+ return self::is_debug_mode() ? $debug_pwd : self::get_app_token();
+ }
+
+ /**
+ * GK Auth user
+ *
+ * @return mixed|string|void
+ */
+ public static function get_gk_api_user() {
+ $user = self::is_debug_mode() ? '2222222222_01' : self::get_setting( 'api_username' );
+
+ return strtolower( $user );
+ }
+
+ /**
+ * GK Auth password
+ *
+ * @return mixed|string|void
+ */
+ public static function get_gk_api_signature() {
+ return self::is_debug_mode() ? 'pass' : self::get_setting( 'api_password' );
+ }
+
+ /**
+ * Retoure Auth user
+ *
+ * @return mixed|string|void
+ */
+ public static function get_retoure_api_user() {
+ $user = self::is_debug_mode() ? '2222222222_Customer' : self::get_setting( 'api_username' );
+
+ return strtolower( $user );
+ }
+
+ public static function get_return_receivers() {
+ $receiver = self::get_setting( 'retoure_receiver_ids' );
+
+ if ( ! empty( $receiver ) ) {
+ return (array) $receiver;
+ } else {
+ return array();
+ }
+ }
+
+ public static function get_return_receiver_by_slug( $slug ) {
+ $receivers = self::get_return_receivers();
+
+ if ( array_key_exists( sanitize_key( $slug ), $receivers ) ) {
+ return $receivers[ $slug ];
+ }
+
+ return false;
+ }
+
+ public static function get_return_receiver_by_country( $country ) {
+ $receivers = self::get_return_receivers();
+ $country_receiver = false;
+ $fallback_receiver = false;
+
+ foreach( $receivers as $receiver ) {
+
+ if ( ! $fallback_receiver && empty( $receiver['country'] ) ) {
+ $fallback_receiver = $receiver;
+ }
+
+ if ( $receiver['country'] === $country ) {
+ $country_receiver = $receiver;
+ }
+ }
+
+ if ( ! $country_receiver ) {
+ $country_receiver = $fallback_receiver;
+ }
+
+ /**
+ * Returns the DHL retoure receiver id for a certain country.
+ *
+ * @param array $receiver The receiver to be used for the retoure.
+ * @param string $country The country code of the retoure.
+ *
+ * @since 3.0.0
+ * @package Vendidero/Germanized/DHL
+ */
+ return apply_filters( 'woocommerce_gzd_dhl_retoure_receiver', $country_receiver, $country );
+ }
+
+ /**
+ * Retoure Auth signature
+ *
+ * @return mixed|string|void
+ */
+ public static function get_retoure_api_signature() {
+ return self::is_debug_mode() ? 'uBQbZ62!ZiBiVVbhc' : self::get_setting( 'api_password' );
+ }
+
+ public static function get_cig_url() {
+ return self::is_debug_mode() ? 'https://cig.dhl.de/services/sandbox/soap' : 'https://cig.dhl.de/services/production/soap';
+ }
+
+ public static function get_rest_url() {
+ return self::is_debug_mode() ? 'https://cig.dhl.de/services/sandbox/rest' : 'https://cig.dhl.de/services/production/rest';
+ }
+
+ public static function get_gk_api_url() {
+ return self::is_debug_mode() ? 'https://cig.dhl.de/cig-wsdls/com/dpdhl/wsdl/geschaeftskundenversand-api/3.1/geschaeftskundenversand-api-3.1.wsdl' : 'https://cig.dhl.de/cig-wsdls/com/dpdhl/wsdl/geschaeftskundenversand-api/3.1/geschaeftskundenversand-api-3.1.wsdl';
+ }
+
+ public static function get_parcel_finder_api_url() {
+ return self::is_debug_mode() ? 'https://cig.dhl.de/cig-wsdls/com/dpdhl/wsdl/standortsuche-api/1.1/standortsuche-api-1.1.wsdl' : 'https://cig.dhl.de/cig-wsdls/com/dpdhl/wsdl/standortsuche-api/1.1/standortsuche-api-1.1.wsdl';
+ }
+
+ public static function get_business_portal_url() {
+ return 'https://www.dhl-geschaeftskundenportal.de';
+ }
+
+ /**
+ * 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 ) );
+ }
+
+ 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 DHL label upload directory. By default
+ * DHL labels are stored in a custom directory under wp-content/uploads.
+ *
+ * @param array $upload_dir Array containing `wp_upload_dir` data.
+ *
+ * @since 3.0.0
+ * @package Vendidero/Germanized/DHL
+ */
+ return apply_filters( 'woocommerce_gzd_dhl_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 DHL label relative upload path.
+ *
+ * @param array $path Relative path.
+ *
+ * @since 3.0.0
+ * @package Vendidero/Germanized/DHL
+ */
+ return apply_filters( 'woocommerce_gzd_dhl_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 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 $file;
+ }
+ }
+
+ public static function get_wsdl_file( $wsdl_link ) {
+ if ( self::is_debug_mode() ) {
+ return $wsdl_link;
+ }
+
+ $main_file = basename( $wsdl_link );
+ $required_files = array( $main_file );
+
+ // Some WSDLs may require multiple files
+ if ( strpos( $wsdl_link, 'geschaeftskundenversand-api' ) !== false ) {
+ $required_files = array(
+ $main_file,
+ str_replace( '.wsdl', '-schema-cis_base.xsd', $main_file ),
+ str_replace( '.wsdl', '-schema-bcs_base.xsd', $main_file ),
+ );
+ }
+
+ $file_link = $wsdl_link;
+ $transient = 'wc_gzd_dhl_wsdl_' . sanitize_key( $main_file );
+ $new_file_name = $main_file;
+ $files_exist = true;
+ $is_zip = false;
+
+ // Renew files every 14 days
+ $transient_valid = DAY_IN_SECONDS * 14;
+
+ if ( sizeof( $required_files ) > 1 ) {
+ $file_link = str_replace( '.wsdl', '.zip', $file_link );
+ $new_file_name = str_replace( '.wsdl', '.zip', $new_file_name );
+ $is_zip = true;
+ }
+
+ /**
+ * Check if all required files exist locally
+ */
+ foreach( $required_files as $file ) {
+ $inner_transient = 'wc_gzd_dhl_wsdl_' . sanitize_key( $file );
+ $file_path = get_transient( $inner_transient );
+
+ if ( $file_path ) {
+ $file_path = \Vendidero\Germanized\Shipments\Package::get_file_by_path( $file_path );
+ }
+
+ if ( ! $file_path || ! file_exists( $file_path ) ) {
+ $files_exist = false;
+ }
+ }
+
+ $file_path = get_transient( $transient );
+
+ /**
+ * This filter may be used to force loading an alternate (local) WSDL file
+ * for a certain API endpoint. By default we are trying to locally store necessary files
+ * to reduce API calls. Transients/files are renewed once per day.
+ *
+ * @param boolean|string $alternate_file In case an alternate file should be used this must be the absolute path.
+ * @param string $wsdl_link The link to the original WSDL file.
+ *
+ * @since 3.1.2
+ * @package Vendidero/Germanized/DHL
+ */
+ $alternate_file = apply_filters( 'woocommerce_gzd_dhl_alternate_wsdl_file', false, $wsdl_link );
+
+ if ( ( $files_exist && $file_path ) || $alternate_file ) {
+ $wsdl_link = $alternate_file ? $alternate_file : \Vendidero\Germanized\Shipments\Package::get_file_by_path( $file_path );
+ } else {
+
+ if ( ! function_exists( 'download_url' ) ) {
+ include_once( ABSPATH . 'wp-admin/includes/file.php' );
+ }
+
+ if ( function_exists( 'download_url' ) && function_exists( 'unzip_file' ) ) {
+ /**
+ * Some URLs like https://prodws.deutschepost.de:8443/ProdWSProvider_1_1/prodws?wsdl might
+ * be rejected due to not using standard SSL ports, e.g.: 8443. Allow them anyway.
+ */
+ add_filter( 'http_request_args', function( $args, $url ) use ( $file_link ) {
+ if ( $url === $file_link ) {
+ $args['reject_unsafe_urls'] = false;
+ }
+
+ return $args;
+ }, 10, 2 );
+
+ $tmp_file = download_url( $file_link, 1500 );
+
+ if ( ! is_wp_error( $tmp_file ) ) {
+
+ $uploads = \Vendidero\Germanized\Shipments\Package::get_upload_dir();
+ $new_file = $uploads['path'] . "/$new_file_name";
+ $has_copied = @copy( $tmp_file, $new_file );
+
+ if ( $has_copied ) {
+
+ if ( $is_zip ) {
+ global $wp_filesystem;
+
+ if ( ! $wp_filesystem ) {
+ WP_Filesystem();
+ }
+
+ $unzipfile = unzip_file( $new_file, $uploads['path'] );
+
+ if ( ! is_wp_error( $unzipfile ) ) {
+ $files_exist = true;
+ $new_wsdl_link = false;
+
+ foreach( $required_files as $file ) {
+ $transient = 'wc_gzd_dhl_wsdl_' . sanitize_key( $file );
+ $file_path = $uploads['path'] . "/$file";
+
+ if ( file_exists( $file_path ) ) {
+ set_transient( $transient, \Vendidero\Germanized\Shipments\Package::get_relative_upload_dir( $file_path ), $transient_valid );
+
+ if ( $file === $main_file ) {
+ $new_wsdl_link = $file_path;
+ }
+ } else {
+ $files_exist = false;
+ }
+ }
+
+ if ( $files_exist && $new_wsdl_link ) {
+ $wsdl_link = $new_wsdl_link;
+ }
+ }
+
+ @unlink( $new_file );
+ } else {
+ $transient = 'wc_gzd_dhl_wsdl_' . sanitize_key( $main_file );
+ $file_path = $uploads['path'] . "/$main_file";
+
+ if ( file_exists( $file_path ) ) {
+ set_transient( $transient, \Vendidero\Germanized\Shipments\Package::get_relative_upload_dir( $file_path ), $transient_valid );
+ $wsdl_link = $file_path;
+ }
+ }
+
+ @unlink( $tmp_file );
+ }
+ }
+ }
+ }
+
+ return $wsdl_link;
+ }
+
+ public static function unset_upload_dir_filter() {
+ remove_filter( 'upload_dir', array( __CLASS__, "filter_upload_dir" ), 150 );
+ }
+
+ public static function filter_upload_dir( $args ) {
+ $upload_base = trailingslashit( $args['basedir'] );
+ $upload_url = trailingslashit( $args['baseurl'] );
+
+ /**
+ * Filter to adjust the DHL label upload path. By default
+ * DHL labels are stored in a custom directory under wp-content/uploads.
+ *
+ * @param string $path Path to the upload directory.
+ *
+ * @since 3.0.0
+ * @package Vendidero/Germanized/DHL
+ */
+ $args['basedir'] = apply_filters( 'woocommerce_gzd_dhl_upload_path', $upload_base . 'wc-gzd-dhl-' . self::get_upload_dir_suffix() );
+ /**
+ * Filter to adjust the DHL label upload URL. By default
+ * DHL labels are stored in a custom directory under wp-content/uploads.
+ *
+ * @param string $url URL to the upload directory.
+ *
+ * @since 3.0.0
+ * @package Vendidero/Germanized/DHL
+ */
+ $args['baseurl'] = apply_filters( 'woocommerce_gzd_dhl_upload_url', $upload_url . 'wc-gzd-dhl-' . self::get_upload_dir_suffix() );
+
+ $args['path'] = $args['basedir'] . $args['subdir'];
+ $args['url'] = $args['baseurl'] . $args['subdir'];
+
+ return $args;
+ }
+
+ public static function get_participation_number( $product ) {
+ return self::get_setting( 'participation_' . $product );
+ }
+
+ /**
+ * @param $name
+ * @param bool|ShippingMethod $method
+ *
+ * @return mixed|void
+ */
+ public static function get_setting( $name, $shipment = false, $default = false ) {
+ $is_dp = false;
+ $value = $default;
+
+ if ( substr( $name, 0, 4 ) === 'dhl_' ) {
+ $name = substr( $name, 4 );
+ } elseif( substr( $name, 0, 14 ) === 'deutsche_post_' ) {
+ $name = substr( $name, 14 );
+ $is_dp = true;
+ }
+
+ if ( ! $is_dp && self::is_debug_mode() ) {
+ if( 'api_username' === $name ) {
+ $name = 'api_sandbox_username';
+ } elseif( 'api_password' === $name ) {
+ $name = 'api_sandbox_password';
+ } elseif( 'account_number' === $name ) {
+ return '2222222222';
+ }
+ }
+
+ if ( ! $is_dp ) {
+ if ( $provider = Package::get_dhl_shipping_provider() ) {
+ if ( $shipment ) {
+ $value = $provider->get_shipment_setting( $shipment, $name, $default );
+ } else {
+ $value = $provider->get_setting( $name, $default );
+ }
+ }
+ } else {
+ if ( $provider = Package::get_deutsche_post_shipping_provider() ) {
+ if ( $shipment ) {
+ $value = $provider->get_shipment_setting( $shipment, $name, $default );
+ } else {
+ $value = $provider->get_setting( $name, $default );
+ }
+ }
+ }
+
+ return $value;
+ }
+
+ public static function log( $message, $type = 'info' ) {
+ $logger = wc_get_logger();
+ $enable_logging = self::enable_logging() ? true : false;
+
+ if ( ! $logger ) {
+ return false;
+ }
+
+ /**
+ * Filter that allows adjusting whether to enable or disable
+ * logging for the DHL package (e.g. API requests).
+ *
+ * @param boolean $enable_logging True if logging should be enabled. False otherwise.
+ *
+ * @package Vendidero/Germanized/DHL
+ */
+ if ( ! apply_filters( 'woocommerce_gzd_dhl_enable_logging', $enable_logging ) ) {
+ return false;
+ }
+
+ if ( ! is_callable( array( $logger, $type ) ) ) {
+ $type = 'info';
+ }
+
+ $logger->{$type}( $message, array( 'source' => 'woocommerce-germanized-dhl' ) );
+ }
+
+ public static function get_available_countries() {
+ return array( 'DE' => _x( 'Germany', 'dhl', 'woocommerce-germanized' ) );
+ }
+
+ public static function get_base_country() {
+ $base_location = wc_get_base_location();
+ $base_country = $base_location['country'];
+
+ /**
+ * Filter to adjust the DHL base country.
+ *
+ * @param string $country The country as ISO code.
+ *
+ * @since 3.0.0
+ * @package Vendidero/Germanized/DHL
+ */
+ return apply_filters( 'woocommerce_gzd_dhl_base_country', $base_country );
+ }
+
+ public static function get_us_territories() {
+ return self::$us_territories;
+ }
+
+ /**
+ * Function return whether the sender and receiver country is the same territory
+ */
+ public static function is_shipping_domestic( $country_receiver ) {
+ // If base is US territory
+ if ( in_array( self::get_base_country(), self::get_us_territories() ) ) {
+ // ...and destination is US territory, then it is "domestic"
+ if ( in_array( $country_receiver, self::get_us_territories() ) ) {
+ return true;
+ } else {
+ return false;
+ }
+ } elseif ( $country_receiver == self::get_base_country() ) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Check if it is an EU shipment
+ */
+ public static function is_eu_shipment( $country_receiver ) {
+ if ( self::is_shipping_domestic( $country_receiver ) ) {
+ return false;
+ }
+
+ if ( in_array( $country_receiver, self::get_eu_countries() ) ) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ protected static function get_eu_countries() {
+ $countries = WC()->countries->get_european_union_countries();
+
+ if ( in_array( 'GB', $countries ) ) {
+ $countries = array_diff( $countries, array( 'GB' ) );
+ }
+
+ return $countries;
+ }
+
+ /**
+ * Function return whether the sender and receiver country is "crossborder" i.e. needs CUSTOMS declarations (outside EU)
+ */
+ public static function is_crossborder_shipment( $country_receiver ) {
+ if ( self::is_shipping_domestic( $country_receiver ) ) {
+ return false;
+ }
+
+ // Is sender country in EU...
+ if ( in_array( self::get_base_country(), self::get_eu_countries() ) ) {
+ // ... and receiver country is in EU means NOT crossborder!
+ if ( in_array( $country_receiver, self::get_eu_countries() ) ) {
+ return false;
+ } else {
+ return true;
+ }
+ } else {
+ return true;
+ }
+ }
+}
diff --git a/packages/woocommerce-germanized-dhl/src/ParcelLocator.php b/packages/woocommerce-germanized-dhl/src/ParcelLocator.php
new file mode 100644
index 000000000..8ea489c8d
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/ParcelLocator.php
@@ -0,0 +1,1126 @@
+ _x( 'Address Type', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'select',
+ 'options' => self::get_address_types(),
+ 'description' => _x( 'Select whether delivery to DHL locations should be enabled.', 'dhl', 'woocommerce-germanized' ),
+ 'class' => '',
+ 'priority' => 50,
+ );
+ $fields['shipping']['fields']['shipping_dhl_postnumber'] = array(
+ 'label' => _x( 'Postnumber', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'description' => _x( 'In case delivery to packstation is selected please fill in the corresponding DHL post number.', 'dhl', 'woocommerce-germanized' ),
+ 'priority' => 60,
+ );
+ return $fields;
+ }
+
+ public static function manipulate_address_fields( $fields ) {
+ global $wp;
+
+ if ( ! self::is_available() ) {
+ return $fields;
+ }
+
+ if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) ) {
+ return $fields;
+ }
+
+ $nonce_key = ( isset( $_REQUEST['woocommerce-edit-address-nonce'] ) ? 'woocommerce-edit-address-nonce' : '_wpnonce' );
+
+ if ( empty( $_POST['action'] ) || 'edit_address' !== $_POST['action'] || empty( $_REQUEST[ $nonce_key ] ) || ! wp_verify_nonce( $_REQUEST[ $nonce_key ], 'woocommerce-edit_address' ) ) {
+ return $fields;
+ }
+
+ $user_id = get_current_user_id();
+
+ if ( $user_id <= 0 ) {
+ return $fields;
+ }
+
+ if ( isset( $_POST['shipping_address_type'] ) && 'dhl' === $_POST['shipping_address_type'] ) {
+ $fields['shipping_address_1']['label'] = self::get_pickup_type_address_label();
+ }
+
+ return $fields;
+ }
+
+ public static function validate_address_postnumber( $value ) {
+
+ if ( ! self::is_available() ) {
+ return $value;
+ }
+
+ $shipping_country = isset( $_POST['shipping_country'] ) ? wc_clean( $_POST['shipping_country'] ) : '';
+ $shipping_address_type = isset( $_POST['shipping_address_type'] ) ? wc_clean( $_POST['shipping_address_type'] ) : 'regular';
+
+ // Not a supported country
+ if ( ! in_array( $shipping_country, self::get_supported_countries() ) ) {
+ return '';
+ }
+
+ if ( 'dhl' === $shipping_address_type ) {
+ $args = array(
+ 'address_1' => isset( $_POST['shipping_address_1'] ) ? wc_clean( $_POST['shipping_address_1'] ) : '',
+ 'postnumber' => isset( $_POST['shipping_dhl_postnumber'] ) ? wc_clean( $_POST['shipping_dhl_postnumber'] ) : '',
+ 'postcode' => isset( $_POST['shipping_postcode'] ) ? wc_clean( $_POST['shipping_postcode'] ) : '',
+ 'city' => isset( $_POST['shipping_city'] ) ? wc_clean( $_POST['shipping_city'] ) : '',
+ 'country' => isset( $_POST['shipping_country'] ) ? wc_clean( $_POST['shipping_country'] ) : '',
+ );
+
+ $result = self::validate_address( $args );
+
+ if ( is_wp_error( $result ) ) {
+ return '';
+ }
+ } else {
+ return '';
+ }
+
+ return self::remove_whitespace( $value );
+ }
+
+ public static function validate_address_fields( $value ) {
+
+ if ( ! self::is_available() ) {
+ return $value;
+ }
+
+ $shipping_country = isset( $_POST['shipping_country'] ) ? wc_clean( $_POST['shipping_country'] ) : '';
+ $shipping_address_type = isset( $_POST['shipping_address_type'] ) ? wc_clean( $_POST['shipping_address_type'] ) : 'regular';
+
+ // Not a supported country
+ if ( ! in_array( $shipping_country, self::get_supported_countries() ) ) {
+ return 'regular';
+ }
+
+ if ( ! array_key_exists( $shipping_address_type, self::get_address_types() ) ) {
+ wc_add_notice( _x( 'Invalid address type.', 'dhl', 'woocommerce-germanized' ), 'error' );
+ }
+
+ if ( 'dhl' === $shipping_address_type ) {
+ $args = array(
+ 'address_1' => isset( $_POST['shipping_address_1'] ) ? wc_clean( $_POST['shipping_address_1'] ) : '',
+ 'postnumber' => isset( $_POST['shipping_dhl_postnumber'] ) ? wc_clean( $_POST['shipping_dhl_postnumber'] ) : '',
+ 'postcode' => isset( $_POST['shipping_postcode'] ) ? wc_clean( $_POST['shipping_postcode'] ) : '',
+ 'city' => isset( $_POST['shipping_city'] ) ? wc_clean( $_POST['shipping_city'] ) : '',
+ 'country' => isset( $_POST['shipping_country'] ) ? wc_clean( $_POST['shipping_country'] ) : '',
+ );
+
+ $result = self::validate_address( $args );
+
+ if ( is_wp_error( $result ) ) {
+ foreach( $result->get_error_messages() as $mesage ) {
+ wc_add_notice( $mesage, 'error' );
+ }
+ }
+ }
+
+ return $value;
+ }
+
+ /**
+ * @param $send_to_pickup
+ * @param $types
+ * @param Shipment $shipment
+ */
+ public static function shipment_has_pickup( $send_to_pickup, $types, $shipment ) {
+ $data = $shipment->get_address();
+
+ if ( isset( $data['address_type'] ) && 'dhl' === $data['address_type'] ) {
+ foreach( $types as $type ) {
+ if ( wc_gzd_dhl_is_pickup_type( $shipment->get_address_1(), $type ) ) {
+ return true;
+ }
+ }
+ }
+
+ return $send_to_pickup;
+ }
+
+ public static function get_postnumber_by_shipment( $shipment ) {
+ if ( is_numeric( $shipment ) ) {
+ $shipment = wc_gzd_get_shipment( $shipment );
+ }
+
+ $postnumber = '';
+
+ if ( $shipment ) {
+ $address = $shipment->get_address();
+
+ if ( isset( $address['dhl_postnumber'] ) ) {
+ $postnumber = $address['dhl_postnumber'];
+ }
+ }
+
+ return self::remove_whitespace( $postnumber );
+ }
+
+ /**
+ * @param WC_Order $order
+ * @param $data
+ */
+ public static function maybe_remove_order_data( $order, $data ) {
+ if ( ! self::order_has_pickup( $order ) ) {
+ $order->delete_meta_data( '_shipping_dhl_postnumber' );
+ $order->update_meta_data( '_shipping_dhl_address_type', 'regular' );
+ }
+ }
+
+ public static function get_supported_countries() {
+ /**
+ * Filter to enable DHL parcel shop delivery for certain countries.
+ *
+ * @param array $country_codes Array of country codes which support DHL parcel shop delivery.
+ *
+ * @package Vendidero/Germanized/DHL
+ */
+ $codes = apply_filters( 'woocommerce_gzd_dhl_parcel_locator_countries', array( 'DE', 'AT' ) );
+
+ return $codes;
+ }
+
+ /**
+ * @param $data
+ * @param $type
+ * @param WC_Order $order
+ *
+ * @return mixed
+ */
+ public static function add_order_address_data( $data, $type, $order ) {
+ if ( 'shipping' === $type ) {
+ if ( self::order_has_pickup( $order ) ) {
+ $data['dhl_postnumber'] = self::get_postnumber_by_order( $order );
+ $data['address_type'] = self::get_shipping_address_type_by_order( $order );
+ }
+ }
+
+ return $data;
+ }
+
+ public static function set_address_format( $formats ) {
+ foreach( self::get_supported_countries() as $country ) {
+
+ if ( ! array_key_exists( $country, $formats ) ) {
+ continue;
+ }
+
+ $format = $formats[ $country ];
+ $format = str_replace( "{name}", "{name}\n{dhl_postnumber}", $format );
+
+ $formats[ $country ] = $format;
+ }
+
+ return $formats;
+ }
+
+ public static function set_formatted_shipping_address( $fields, $order ) {
+ if ( ! empty( $fields ) && is_array( $fields ) ) {
+ $fields['dhl_postnumber'] = '';
+
+ if ( wc_gzd_dhl_order_has_pickup( $order ) ) {
+ $fields['dhl_postnumber'] = self::get_postnumber_by_order( $order );
+ }
+ }
+
+ return $fields;
+ }
+
+ public static function get_postnumber_by_order( $order ) {
+ if ( is_numeric( $order ) ) {
+ $order = wc_get_order( $order );
+ }
+
+ $post_number = '';
+
+ if ( $order ) {
+ if ( $order->get_meta( '_shipping_dhl_postnumber' ) ) {
+ $post_number = $order->get_meta( '_shipping_dhl_postnumber' );
+ }
+ }
+
+ /**
+ * Filter to adjust the DHL postnumber for a certain order.
+ *
+ * @param string $post_number The post number.
+ * @param WC_Order $order The order object.
+ *
+ * @since 3.0.0
+ * @package Vendidero/Germanized/DHL
+ */
+ return apply_filters( 'woocommerce_gzd_dhl_order_postnumber', $post_number, $order );
+ }
+
+ public static function get_shipping_address_type_by_order( $order ) {
+ if ( is_numeric( $order ) ) {
+ $order = wc_get_order( $order );
+ }
+
+ $address_type = 'regular';
+
+ if ( $order ) {
+ if ( $type = $order->get_meta( '_shipping_address_type' ) ) {
+ if ( array_key_exists( $type, self::get_address_types() ) ) {
+ $address_type = $type;
+ }
+ }
+ }
+
+ return $address_type;
+ }
+
+ public static function order_has_pickup( $order ) {
+ if ( is_numeric( $order ) ) {
+ $order = wc_get_order( $order );
+ }
+
+ $has_pickup = false;
+
+ if ( $order ) {
+ $address_type = self::get_shipping_address_type_by_order( $order );
+ $number = self::get_postnumber_by_order( $order );
+ $type = self::get_pickup_type_by_order( $order );
+ $country = $order->get_shipping_country();
+
+ if ( ! empty( $country ) && in_array( $country, self::get_supported_countries() ) && 'dhl' === $address_type && ! empty( $number ) && ! empty( $type ) ) {
+ $has_pickup = true;
+ }
+ }
+
+ return $has_pickup;
+ }
+
+ public static function get_pickup_type_by_order( $order ) {
+ if ( is_numeric( $order ) ) {
+ $order = wc_get_order( $order );
+ }
+
+ $pickup_type = '';
+
+ if ( $order ) {
+ if ( $address = $order->get_shipping_address_1() ) {
+ $pickup_types = wc_gzd_dhl_get_pickup_types();
+
+ foreach( $pickup_types as $pickup_tmp_type => $label ) {
+ if ( wc_gzd_dhl_is_pickup_type( $address, $pickup_tmp_type ) ) {
+ $pickup_type = $pickup_tmp_type;
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Filter to adjust the DHL pickup type e.g. packstation for a certain order.
+ *
+ * @see wc_gzd_dhl_get_pickup_types()
+ *
+ * @param string $pickup_type The pickup type.
+ * @param WC_Order $order The order object.
+ *
+ * @since 3.0.0
+ * @package Vendidero/Germanized/DHL
+ */
+ return apply_filters( 'woocommerce_gzd_dhl_order_pickup_type', $pickup_type, $order );
+ }
+
+ public static function get_postnumber_by_user( $user ) {
+ if ( is_numeric( $user ) ) {
+ $user = get_user_by( 'ID', $user );
+ }
+
+ $post_number = '';
+
+ if ( $user ) {
+
+ if ( get_user_meta( $user->ID, 'shipping_dhl_postnumber', true ) ) {
+ $post_number = get_user_meta( $user->ID, 'shipping_dhl_postnumber', true );
+ }
+
+ if ( get_user_meta( $user->ID, 'shipping_parcelshop_post_number', true ) ) {
+ $post_number = get_user_meta( $user->ID, 'shipping_parcelshop_post_number', true );
+ }
+ }
+
+ /**
+ * Filter to adjust the DHL postnumber for a certain user.
+ *
+ * @param string $post_number The post number.
+ * @param WP_User $user The user object.
+ *
+ * @since 3.0.0
+ * @package Vendidero/Germanized/DHL
+ */
+ return apply_filters( 'woocommerce_gzd_dhl_user_postnumber', $post_number, $user );
+ }
+
+ public static function set_formatted_billing_address( $fields, $order ) {
+
+ if ( ! empty( $fields ) && is_array( $fields ) ) {
+ $fields['dhl_postnumber'] = '';
+ }
+
+ return $fields;
+ }
+
+ public static function set_formatted_address( $placeholder, $args ) {
+ if ( isset( $args['dhl_postnumber'] ) ) {
+ $placeholder['{dhl_postnumber}'] = $args['dhl_postnumber'];
+ $placeholder['{dhl_postnumber_upper}'] = strtoupper( $args['dhl_postnumber'] );
+ } else {
+ $placeholder['{dhl_postnumber}'] = '';
+ $placeholder['{dhl_postnumber}'] = '';
+ }
+ return $placeholder;
+ }
+
+ public static function set_user_address( $address, $customer_id, $name ) {
+ if ( 'shipping' === $name ) {
+ if ( $post_number = self::get_postnumber_by_user( $customer_id ) ) {
+ $address['dhl_postnumber'] = $post_number;
+ }
+ }
+ return $address;
+ }
+
+ public static function manipulate_checkout_fields() {
+ if ( 'dhl' === WC()->checkout()->get_value( 'shipping_address_type' ) ) {
+ add_filter( 'woocommerce_checkout_fields', array( __CLASS__, 'switch_street_label' ), 10, 1 );
+ } else {
+ remove_filter( 'woocommerce_checkout_fields', array( __CLASS__, 'switch_street_label' ), 10 );
+ }
+ }
+
+ public static function switch_street_label( $fields ) {
+ $fields['shipping']['shipping_address_1']['label'] = self::get_type_text( ' / ' );
+
+ return $fields;
+ }
+
+ protected static function get_rate_with_instance_id( $rate_id ) {
+ if ( strpos( $rate_id, ':' ) === false ) {
+ $rate_id = $rate_id . ':0';
+ }
+
+ return $rate_id;
+ }
+
+ public static function get_shipping_method_data( $from_session = false ) {
+
+ if ( $from_session ) {
+ return WC()->session->get( 'dhl_shipping_method_data', array() );
+ }
+
+ if ( WC()->session ) {
+ unset( WC()->session->dhl_shipping_method_data );
+ }
+
+ $packages = WC()->shipping()->get_packages();
+ $data = array();
+
+ foreach( $packages as $package ) {
+ $rates = $package['rates'];
+
+ foreach( $rates as $rate ) {
+ if ( $method = wc_gzd_dhl_get_shipping_method( $rate ) ) {
+ $supports = array();
+
+ foreach( wc_gzd_dhl_get_pickup_types() as $pickup_type => $title ) {
+ $getter = "is_{$pickup_type}_enabled";
+
+ if ( $method->$getter() ) {
+ $supports[] = $pickup_type;
+ }
+ }
+
+ $data[ self::get_rate_with_instance_id( $rate->id ) ] = array(
+ 'supports' => $supports,
+ 'address_type_options' => self::get_address_types( $method ),
+ 'finder_button' => self::get_button( $method ),
+ 'street_label' => self::get_pickup_type_address_label( $method ),
+ 'street_placeholder' => self::get_pickup_type_address_placeholder( $method ),
+ );
+ }
+ }
+ }
+
+ if ( WC()->session ) {
+ WC()->session->set( 'dhl_shipping_method_data', $data );
+ }
+
+ return $data;
+ }
+
+ protected static function remove_whitespace( $str ) {
+ return trim( preg_replace('/\s+/', '', $str ) );
+ }
+
+ public static function format_address_data( $data ) {
+ if ( isset( $data['shipping_dhl_postnumber'] ) ) {
+ $data['shipping_dhl_postnumber'] = self::remove_whitespace( $data['shipping_dhl_postnumber'] );
+ }
+
+ return $data;
+ }
+
+ public static function validate_checkout() {
+ if ( ! self::is_available() ) {
+ return;
+ }
+
+ $data = WC_Checkout::instance()->get_posted_data();
+ $errors = new WP_Error();
+
+ // Validate input only if "ship to different address" flag is set
+ if ( ! isset( $data['ship_to_different_address'] ) || ! $data['ship_to_different_address'] ) {
+ return;
+ }
+
+ $shipping_country = isset( $data['shipping_country'] ) ? $data['shipping_country'] : '';
+ $shipping_address_type = isset( $data['shipping_address_type'] ) ? wc_clean( $data['shipping_address_type'] ) : 'regular';
+
+ if ( empty( $shipping_address_type ) ) {
+ $shipping_address_type = 'regular';
+ }
+
+ // Not a supported country
+ if ( ! in_array( $shipping_country, self::get_supported_countries() ) ) {
+ $data['shipping_dhl_postnumber'] = '';
+ return;
+ }
+
+ if ( ! array_key_exists( $shipping_address_type, self::get_address_types() ) ) {
+ $errors->add( 'validation', _x( 'Invalid address type.', 'dhl', 'woocommerce-germanized' ) );
+ }
+
+ if ( 'dhl' === $shipping_address_type ) {
+
+ $args = array(
+ 'address_1' => isset( $data['shipping_address_1'] ) ? wc_clean( $data['shipping_address_1'] ) : '',
+ 'postnumber' => isset( $data['shipping_dhl_postnumber'] ) ? wc_clean( $data['shipping_dhl_postnumber'] ) : '',
+ 'postcode' => isset( $data['shipping_postcode'] ) ? wc_clean( $data['shipping_postcode'] ) : '',
+ 'city' => isset( $data['shipping_city'] ) ? wc_clean( $data['shipping_city'] ) : '',
+ 'country' => isset( $data['shipping_country'] ) ? wc_clean( $data['shipping_country'] ) : '',
+ );
+
+ $result = self::validate_address( $args );
+
+ if ( is_wp_error( $result ) ) {
+ foreach( $result->get_error_messages() as $mesage ) {
+ $errors->add( 'validation', $mesage );
+ }
+ }
+ }
+
+ if ( wc_gzd_dhl_wp_error_has_errors( $errors ) ) {
+ foreach( $errors->get_error_messages() as $message ) {
+ wc_add_notice( $message, 'error' );
+ }
+ }
+ }
+
+ protected static function get_available_pickup_types() {
+ $pickup_types = wc_gzd_dhl_get_pickup_types();
+
+ if ( isset( $pickup_types['packstation'] ) && ! self::is_packstation_enabled() ) {
+ unset( $pickup_types['packstation'] );
+ }
+
+ if ( isset( $pickup_types['postoffice'] ) && ! self::is_postoffice_enabled() ) {
+ unset( $pickup_types['postoffice'] );
+ }
+
+ if ( isset( $pickup_types['parcelshop'] ) && ! self::is_parcelshop_enabled() ) {
+ unset( $pickup_types['parcelshop'] );
+ }
+
+ return $pickup_types;
+ }
+
+ protected static function validate_address( $args ) {
+ $args = wp_parse_args( $args, array(
+ 'address_1' => '',
+ 'postnumber' => '',
+ 'postcode' => '',
+ 'city' => '',
+ 'country' => '',
+ ) );
+
+ $has_postnumber = false;
+
+ if ( ! empty( $args['postnumber'] ) ) {
+ $has_postnumber = true;
+
+ // Do only allow numeric input
+ $args['postnumber'] = preg_replace( "/[^0-9]/", "", $args['postnumber'] );
+ }
+
+ $error = new WP_Error();
+ $is_packstation = false;
+ $pickup_number = preg_replace( "/[^0-9]/", "", $args['address_1'] );
+
+ /**
+ * A number is required for the packstation/parcelshop/postoffice
+ */
+ if ( empty( $pickup_number ) && ! empty( $args['address_1'] ) ) {
+ $error->add( 'validation', sprintf( _x( 'Please provide a valid number within the %s field.', 'dhl', 'woocommerce-germanized' ), self::get_type_text( ' / ' ) ) );
+ }
+
+ if ( wc_gzd_dhl_is_pickup_type( $args['address_1'], 'packstation' ) ) {
+ $is_packstation = true;
+
+ if ( ! self::is_packstation_enabled() ) {
+ $error->add( 'validation', _x( 'Sorry, but delivery to packstation is not available.', 'dhl', 'woocommerce-germanized' ) );
+ $is_packstation = false;
+ }
+ } elseif( wc_gzd_dhl_is_pickup_type( $args['address_1'], 'parcelshop' ) ) {
+ if ( ! self::is_parcelshop_enabled() ) {
+ $error->add( 'validation', _x( 'Sorry, but delivery to parcel shops is not available.', 'dhl', 'woocommerce-germanized' ) );
+ }
+ } elseif( wc_gzd_dhl_is_pickup_type( $args['address_1'], 'postoffice' ) ) {
+ if ( ! self::is_postoffice_enabled() ) {
+ $error->add( 'validation', _x( 'Sorry, but delivery to post offices is not available.', 'dhl', 'woocommerce-germanized' ) );
+ }
+ } else {
+ // Try validation
+ $valid = false;
+
+ if ( ! $valid ) {
+ $error->add( 'validation', sprintf( _x( 'Please indicate shipment to %s by one of the following values: %s.', 'dhl', 'woocommerce-germanized' ), self::get_type_text( ' / ' ), implode( ', ', array_unique( array_values( self::get_available_pickup_types() ) ) ) ) );
+ }
+ }
+
+ if ( $has_postnumber && ! empty( $args['postnumber'] ) ) {
+ $post_number_len = strlen( $args['postnumber'] );
+
+ if ( $post_number_len < 6 || $post_number_len > 12 ) {
+ $error->add( 'validation', _x( 'Your DHL customer number (Post number) is not valid. Please check your number.', 'dhl', 'woocommerce-germanized' ) );
+ }
+ } elseif( ( $is_packstation || $has_postnumber ) && empty( $args['postnumber'] ) ) {
+ $error->add( 'validation', _x( 'Your DHL customer number (Post number) is needed to ship to a packstation.', 'dhl', 'woocommerce-germanized' ) );
+ }
+
+ return wc_gzd_dhl_wp_error_has_errors( $error ) ? $error : true;
+ }
+
+ public static function add_inline_styles() {
+
+ // load scripts on checkout page only
+ if ( ! is_checkout() && ! is_wc_endpoint_url( 'edit-address' ) ) {
+ return;
+ }
+
+ echo '';
+ }
+
+ public static function localize_printed_scripts() {
+ /**
+ * Do not check for localized script as this script needs to be loadeed in footer to make sure
+ * that shipping method data (packages etc.) exist. This may lead to duplicate localizations (which is not a bug).
+ */
+ if ( wp_script_is( 'wc-gzd-parcel-locator-dhl' ) ) {
+ self::$localized_scripts[] = 'wc-gzd-parcel-locator-dhl';
+
+ wp_localize_script( 'wc-gzd-parcel-locator-dhl', 'wc_gzd_dhl_parcel_locator_params', array(
+ 'ajax_url' => admin_url( 'admin-ajax.php' ),
+ 'parcel_locator_nonce' => wp_create_nonce('dhl-parcel-locator' ),
+ 'parcel_locator_data_nonce' => wp_create_nonce('dhl-parcel-locator-shipping-data' ),
+ 'supported_countries' => self::get_supported_countries(),
+ 'methods' => is_checkout() ? self::get_shipping_method_data() : array(),
+ 'is_checkout' => is_checkout(),
+ 'pickup_types' => wc_gzd_dhl_get_pickup_types(),
+ 'i18n' => array_merge( wc_gzd_dhl_get_pickup_types(), array() ),
+ 'wrapper' => is_checkout() ? '.woocommerce-checkout' : '.woocommerce-address-fields',
+ ) );
+ }
+
+ if ( ! in_array( 'wc-gzd-parcel-finder-dhl', self::$localized_scripts, true ) && wp_script_is( 'wc-gzd-parcel-finder-dhl' ) ) {
+ self::$localized_scripts[] = 'wc-gzd-parcel-finder-dhl';
+
+ wp_localize_script( 'wc-gzd-parcel-finder-dhl', 'wc_gzd_dhl_parcel_finder_params', array(
+ 'parcel_finder_nonce' => wp_create_nonce('dhl-parcel-finder' ),
+ 'ajax_url' => admin_url( 'admin-ajax.php' ),
+ 'packstation_icon' => Package::get_assets_url() . '/img/packstation.png',
+ 'parcelshop_icon' => Package::get_assets_url() . '/img/parcelshop.png',
+ 'postoffice_icon' => Package::get_assets_url() . '/img/post_office.png',
+ 'api_key' => self::get_setting( 'map_api_password' ),
+ 'wrapper' => is_checkout() ? '.woocommerce-checkout' : '.woocommerce-address-fields',
+ 'i18n' => array_merge( wc_gzd_dhl_get_pickup_types(), array(
+ 'branch' => _x( 'Branch', 'dhl', 'woocommerce-germanized' ),
+ 'post_number' => _x( 'Postnumber ', 'dhl', 'woocommerce-germanized' ),
+ ) ),
+ ) );
+ }
+ }
+
+ public static function add_scripts() {
+
+ // load scripts on checkout page only
+ if ( ! is_checkout() && ! is_wc_endpoint_url( 'edit-address' ) ) {
+ return;
+ }
+
+ $deps = array( 'jquery' );
+ $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
+
+ if ( is_checkout() ) {
+ array_push( $deps, 'wc-checkout' );
+ }
+
+ wp_register_script( 'wc-gzd-parcel-locator-dhl', Package::get_assets_url() . '/js/parcel-locator' . $suffix . '.js', $deps, Package::get_version(), true );
+ wp_register_script( 'wc-gzd-parcel-finder-dhl', Package::get_assets_url() . '/js/parcel-finder' . $suffix . '.js', array( 'jquery-blockui', 'wc-gzd-parcel-locator-dhl' ), Package::get_version(), true );
+
+ wp_register_style( 'wc-gzd-parcel-finder-dhl', Package::get_assets_url() . '/css/parcel-finder' . $suffix . '.css', array(), Package::get_version() );
+
+ if ( self::has_map() ) {
+ wp_enqueue_script( 'wc-gzd-parcel-finder-dhl' );
+ wp_enqueue_style( 'wc-gzd-parcel-finder-dhl' );
+ }
+
+ wp_enqueue_script( 'wc-gzd-parcel-locator-dhl' );
+ }
+
+ protected static function disable_method_setting() {
+ $disable_method_check = ( is_account_page() || is_admin() );
+ $is_forced_checkout = isset( $_POST['is_checkout'] ) ? wc_string_to_bool( $_POST['is_checkout'] ) : true;
+
+ if ( is_ajax() && $is_forced_checkout ) {
+ $disable_method_check = false;
+ }
+
+ return $disable_method_check;
+ }
+
+ protected static function get_setting( $key, $check_method = true ) {
+ $option_key = 'parcel_pickup_' . $key;
+
+ /**
+ * Exclude non-overridable options to make sure they might be used for DP too (e.g. packstation maps)
+ */
+ if ( ! in_array( $option_key, array( 'parcel_pickup_map_enable', 'parcel_pickup_map_api_password', 'parcel_pickup_map_max_results' ) ) ) {
+ if ( $check_method && ( $method = wc_gzd_dhl_get_current_shipping_method() ) ) {
+ if ( 'parcel_pickup_packstation_enable' === $option_key ) {
+ return wc_bool_to_string( $method->is_packstation_enabled() );
+ } elseif ( 'parcel_pickup_parcelshop_enable' === $option_key ) {
+ return wc_bool_to_string( $method->is_parcelshop_enabled() );
+ } elseif ( 'parcel_pickup_postoffice_enable' === $option_key ) {
+ return wc_bool_to_string( $method->is_postoffice_enabled() );
+ } elseif ( ! self::disable_method_setting() ) {
+ /**
+ * Explicitly call available pickup getters instead of generic get_option method
+ * to support DP adjustments (packstation).
+ */
+ return $method->get_option( $option_key );
+ }
+ }
+ }
+
+ $setting = Package::get_setting( $option_key );
+
+ return $setting;
+ }
+
+ public static function is_enabled() {
+ return Package::base_country_supports( 'pickup' );
+ }
+
+ public static function is_available( $check_shipping_method = true ) {
+ return self::is_packstation_enabled( $check_shipping_method ) || self::is_parcelshop_enabled( $check_shipping_method ) || self::is_postoffice_enabled( $check_shipping_method );
+ }
+
+ public static function is_postoffice_enabled( $check_shipping_method = true ) {
+ return 'yes' === self::get_setting( 'postoffice_enable', $check_shipping_method );
+ }
+
+ public static function is_packstation_enabled( $check_shipping_method = true ) {
+ return 'yes' === self::get_setting( 'packstation_enable', $check_shipping_method );
+ }
+
+ public static function is_parcelshop_enabled( $check_shipping_method = true ) {
+ return 'yes' === self::get_setting( 'parcelshop_enable', $check_shipping_method );
+ }
+
+ public static function has_map( $check_shipping_method = true ) {
+ $api_key = self::get_setting( 'map_api_password', false );
+
+ return ( 'yes' === self::get_setting( 'map_enable', $check_shipping_method ) && ! empty( $api_key ) && Package::is_dhl_enabled() );
+ }
+
+ public static function get_max_results() {
+ return self::get_setting( 'map_max_results' );
+ }
+
+ protected static function get_street_placeholder( $method = false ) {
+ $type = '';
+ $text = '';
+
+ if ( ( $method && $method->is_packstation_enabled() ) || ( ! $method && self::is_packstation_enabled() ) ) {
+ $type = wc_gzd_dhl_get_pickup_type( 'packstation' );
+ } elseif ( ( $method && $method->is_parcelshop_enabled() ) || ( ! $method && self::is_parcelshop_enabled() ) ) {
+ $type = wc_gzd_dhl_get_pickup_type( 'parcelshop' );
+ } elseif ( ( $method && $method->is_postoffice_enabled() ) || ( ! $method && self::is_postoffice_enabled() ) ) {
+ $type = wc_gzd_dhl_get_pickup_type( 'postoffice' );
+ }
+
+ if ( ! empty( $type ) ) {
+ $text = sprintf( _x( 'e.g. %s 456', 'dhl', 'woocommerce-germanized' ), $type );
+ }
+
+ return $text;
+ }
+
+ /**
+ * @param string $sep
+ * @param bool $plural
+ * @param bool|ShippingMethod $method
+ *
+ * @return string
+ */
+ protected static function get_type_text( $sep = '', $plural = true, $method = false ) {
+ $search_types = '';
+
+ if ( empty( $sep ) ) {
+ $sep = '&';
+ }
+
+ if ( ( $method && $method->is_packstation_enabled() ) || ( ! $method && self::is_packstation_enabled() ) ) {
+ $search_types .= _x( 'Packstation', 'dhl', 'woocommerce-germanized' );
+ }
+
+ if ( ( $method && ( $method->is_parcelshop_enabled() || $method->is_postoffice_enabled() ) ) || ( ! $method && ( self::is_parcelshop_enabled() || self::is_postoffice_enabled() ) ) ) {
+ $branch_type = ( $plural ) ? _x( 'Branches', 'dhl', 'woocommerce-germanized' ) : _x( 'Branch', 'dhl', 'woocommerce-germanized' );
+ $search_types .= ( ! empty( $search_types ) ? ' ' . $sep . ' ' . $branch_type : $branch_type );
+ }
+
+ return $search_types;
+ }
+
+ public static function add_admin_shipping_fields( $fields ) {
+ $fields['address_type'] = array(
+ 'label' => _x( 'Address Type', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'select',
+ 'show' => false,
+ 'options' => self::get_address_types()
+ );
+
+ $fields['dhl_postnumber'] = array(
+ 'label' => _x( 'DHL customer number (Post number)', 'dhl', 'woocommerce-germanized' ),
+ 'show' => false,
+ 'type' => 'text',
+ );
+
+ return $fields;
+ }
+
+ public static function get_address_types( $method = false ) {
+ return array(
+ 'regular' => _x( 'Regular Address', 'dhl', 'woocommerce-germanized' ),
+ 'dhl' => self::get_type_text( ' / ', true, $method )
+ );
+ }
+
+ public static function add_shipping_fields( $fields ) {
+ /**
+ * On initial render make sure to not check the actual shipping method options for availability.
+ * Otherwise if the initial shipping method does not support DHL the fields are not even added to the checkout form.
+ */
+ if ( self::is_available( false ) ) {
+ $fields['shipping_address_type'] = array(
+ 'label' => _x( 'Address Type', 'dhl', 'woocommerce-germanized' ),
+ 'required' => false,
+ 'type' => 'select',
+ 'class' => array( 'shipping-dhl-address-type' ),
+ 'clear' => true,
+ 'priority' => 5,
+ 'options' => self::get_address_types(),
+ 'default' => 'regular',
+ );
+
+ $fields['shipping_dhl_postnumber'] = array(
+ 'label' => _x( 'DHL customer number (Post number)', 'dhl', 'woocommerce-germanized' ),
+ 'required' => false,
+ 'type' => 'text',
+ 'class' => array( 'shipping-dhl-postnumber' ),
+ 'description' => _x( 'Not yet a DHL customer?', 'dhl', 'woocommerce-germanized' ) . '' . _x( 'Register now', 'dhl', 'woocommerce-germanized' ) . ' ',
+ 'clear' => true,
+ 'priority' => 45,
+ );
+
+ $fields['shipping_address_1']['custom_attributes'] = ( isset( $fields['shipping_address_1']['custom_attributes'] ) ? $fields['shipping_address_1']['custom_attributes'] : array() );
+ $fields['shipping_address_1']['custom_attributes']['data-label-dhl'] = self::get_pickup_type_address_label();
+ $fields['shipping_address_1']['custom_attributes']['data-label-regular'] = $fields['shipping_address_1']['label'];
+ $fields['shipping_address_1']['custom_attributes']['data-placeholder-dhl'] = self::get_pickup_type_address_placeholder();
+ $fields['shipping_address_1']['custom_attributes']['data-placeholder-regular'] = isset( $fields['shipping_address_1']['placeholder'] ) ? $fields['shipping_address_1']['placeholder'] : '';
+ $fields['shipping_address_1']['custom_attributes']['data-desc-dhl'] = self::get_button();
+ }
+
+ return $fields;
+ }
+
+ protected static function get_pickup_type_address_label( $method = false ) {
+ /**
+ * Filter to adjust the pickup type address label added
+ * to the address field when a certain pickup type was chosen.
+ *
+ * @param string $pickup_type_text The pickup type text.
+ * @param boolean|ShippingMethod $method The shipping method object if available.
+ *
+ * @since 3.0.0
+ * @package Vendidero/Germanized/DHL
+ */
+ return apply_filters( 'woocommerce_gzd_dhl_pickup_type_address_label', self::get_type_text( ' / ', false, $method ), $method );
+ }
+
+ protected static function get_pickup_type_address_placeholder( $method = false ) {
+ /**
+ * Filter to adjust the pickup type address placeholder added
+ * to the address field when a certain pickup type was chosen.
+ *
+ * @param string $pickup_type_text The pickup type placeholder text.
+ * @param boolean|ShippingMethod $method The shipping method object if available.
+ *
+ * @since 3.0.0
+ * @package Vendidero/Germanized/DHL
+ */
+ return apply_filters( 'woocommerce_gzd_dhl_pickup_type_address_placeholder', self::get_street_placeholder( $method ), $method );
+ }
+
+ protected static function get_icon( $type = 'packstation' ) {
+ return Package::get_assets_url() . '/img/' . $type . '.png';
+ }
+
+ protected static function get_button_text( $method = false ) {
+ $text = sprintf( _x( 'Search %s', 'dhl', 'woocommerce-germanized' ), self::get_type_text( '', true, $method ) );
+
+ return $text;
+ }
+
+ protected static function get_button( $method = false ) {
+ $text = self::get_button_text( $method );
+
+ if ( self::has_map() ) {
+ return '' . $text . ' ';
+ } else {
+ return '' . $text . ' ';
+ }
+ }
+
+ protected static function get_pickup_locator_link() {
+ return 'https://www.dhl.de/de/privatkunden/dhl-standorte-finden.html';
+ }
+
+ public static function add_button() {
+ echo self::get_button();
+ }
+
+ public static function add_form() {
+
+ if ( ! is_checkout() && ! is_wc_endpoint_url( 'edit-address' ) ) {
+ return;
+ }
+
+ $args = array(
+ 'img_packstation' => self::get_icon( 'packstation' ),
+ 'img_postoffice' => self::get_icon( 'post_office' ),
+ 'img_parcelshop' => self::get_icon( 'parcelshop' ),
+ 'is_packstation_enabled' => self::is_packstation_enabled(),
+ 'is_postoffice_enabled' => self::is_postoffice_enabled(),
+ 'is_parcelshop_enabled' => self::is_parcelshop_enabled(),
+ );
+
+ wc_get_template( 'checkout/dhl/parcel-finder.php', $args, Package::get_template_path(), Package::get_path() . '/templates/' );
+ }
+
+ public static function ajax_refresh_shipping_data() {
+ check_ajax_referer( 'dhl-parcel-locator-shipping-data', 'security' );
+
+ wp_send_json( array(
+ 'methods' => self::get_shipping_method_data( true ),
+ 'success' => true,
+ ) );
+ }
+
+ public static function ajax_validate_address() {
+
+ check_ajax_referer( 'dhl-parcel-locator', 'security' );
+
+ $country = isset( $_POST['country'] ) ? wc_clean( $_POST['country'] ) : Package::get_base_country();
+ $postcode = isset( $_POST['postcode'] ) ? wc_clean( $_POST['postcode'] ) : '';
+ $city = isset( $_POST['city'] ) ? wc_clean( $_POST['city'] ) : '';
+ $address = isset( $_POST['address'] ) ? wc_clean( $_POST['address'] ) : '';
+
+ wp_send_json( array(
+ 'valid' => true,
+ 'address' => $address,
+ 'success' => true,
+ ) );
+ }
+
+ public static function ajax_search() {
+
+ check_ajax_referer( 'dhl-parcel-finder', 'security' );
+
+ $parcelfinder_country = isset( $_POST['dhl_parcelfinder_country'] ) ? wc_clean( $_POST['dhl_parcelfinder_country'] ) : Package::get_base_country();
+ $parcelfinder_postcode = isset( $_POST['dhl_parcelfinder_postcode'] ) ? wc_clean( $_POST['dhl_parcelfinder_postcode'] ) : '';
+ $parcelfinder_city = isset( $_POST['dhl_parcelfinder_city'] ) ? wc_clean( $_POST['dhl_parcelfinder_city'] ) : '';
+ $parcelfinder_address = isset( $_POST['dhl_parcelfinder_address'] ) ? wc_clean( $_POST['dhl_parcelfinder_address'] ) : '';
+
+ $packstation_filter = wc_string_to_bool( isset( $_POST['dhl_parcelfinder_packstation_filter'] ) ? wc_clean( $_POST['dhl_parcelfinder_packstation_filter'] ) : 'no' );
+ $parcelshop_filter = wc_string_to_bool( isset( $_POST['dhl_parcelfinder_parcelshop_filter'] ) ? wc_clean( $_POST['dhl_parcelfinder_parcelshop_filter'] ) : 'no' );
+ $postoffice_filter = wc_string_to_bool( isset( $_POST['dhl_parcelfinder_postoffice_filter'] ) ? wc_clean( $_POST['dhl_parcelfinder_postoffice_filter'] ) : 'no' );
+
+ try {
+ $args = array(
+ 'address' => $parcelfinder_address,
+ 'zip' => $parcelfinder_postcode,
+ 'city' => $parcelfinder_city,
+ 'country' => empty( $parcelfinder_country ) ? Package::get_base_country() : $parcelfinder_country,
+ );
+
+ $error = new WP_Error();
+ $types = array();
+
+ if ( $packstation_filter && self::is_packstation_enabled() ) {
+ $types[] = 'packstation';
+ }
+
+ if ( $parcelshop_filter && self::is_parcelshop_enabled() ) {
+ $types[] = 'parcelshop';
+ }
+
+ if ( $postoffice_filter && self::is_postoffice_enabled() ) {
+ $types[] = 'postoffice';
+ }
+
+ $parcel_res = Package::get_api()->get_parcel_location( $args, $types );
+
+ if ( empty( $parcel_res ) ) {
+ $error->add( 404, _x( 'No DHL locations found', 'dhl', 'woocommerce-germanized' ) );
+ }
+
+ if ( ! wc_gzd_dhl_wp_error_has_errors( $error ) ) {
+ wp_send_json( array(
+ 'parcel_shops' => $parcel_res,
+ 'success' => true,
+ ) );
+ } else {
+ wp_send_json( array(
+ 'success' => false,
+ 'messages' => $error->get_error_messages(),
+ ) );
+ }
+ } catch ( Exception $e ) {
+ $error = sprintf( _x( 'There was an error while communicating with DHL. Please manually find a %s or %s.', 'dhl', 'woocommerce-germanized' ), '' . _x( 'DHL location', 'dhl', 'woocommerce-germanized' ) . ' ', '' . _x( 'retry', 'dhl', 'woocommerce-germanized' ) . ' ' );
+
+ wp_send_json( array(
+ 'success' => false,
+ 'message' => Package::is_debug_mode() ? $e->getMessage() : $error,
+ ) );
+ }
+
+ wp_die();
+ }
+}
diff --git a/packages/woocommerce-germanized-dhl/src/ParcelServices.php b/packages/woocommerce-germanized-dhl/src/ParcelServices.php
new file mode 100644
index 000000000..dd42d058a
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/ParcelServices.php
@@ -0,0 +1,394 @@
+has_preferred_day() ) {
+ $new_rows['preferred_day'] = array(
+ 'label' => _x( 'Preferred Day', 'dhl', 'woocommerce-germanized' ),
+ 'value' => wc_format_datetime( $dhl_order->get_preferred_day(), wc_date_format() ),
+ );
+ }
+
+ if ( $dhl_order->has_preferred_time() ) {
+ $new_rows['preferred_time'] = array(
+ 'label' => _x( 'Preferred Time', 'dhl', 'woocommerce-germanized' ),
+ 'value' => $dhl_order->get_preferred_time(),
+ );
+ }
+
+ if ( $dhl_order->has_preferred_location() ) {
+ $new_rows['preferred_location'] = array(
+ 'label' => _x( 'Preferred Location', 'dhl', 'woocommerce-germanized' ),
+ 'value' => $dhl_order->get_preferred_location(),
+ );
+ } elseif( $dhl_order->has_preferred_neighbor() ) {
+ $new_rows['preferred_neighbor'] = array(
+ 'label' => _x( 'Preferred Neighbor', 'dhl', 'woocommerce-germanized' ),
+ 'value' => $dhl_order->get_preferred_neighbor_formatted_address(),
+ );
+ }
+ }
+
+ if ( ! empty( $new_rows ) ) {
+
+ // Instert before payment method
+ $insert_before = array_search( 'payment_method', array_keys( $total_rows ) );
+
+ // If no payment method, insert before order total
+ if ( empty( $insert_before ) ) {
+ $insert_before = array_search( 'order_total', array_keys( $total_rows ) );
+ }
+
+ if ( empty( $insert_before ) ) {
+ $total_rows += $new_rows;
+ } else {
+ $first_array = array_splice( $total_rows, 0, $insert_before );
+ $total_rows = array_merge( $first_array, $new_rows, $total_rows );
+ }
+ }
+
+ return $total_rows;
+ }
+
+ public static function create_order( $order ) {
+ $posted_data = $_POST;
+
+ if ( self::is_preferred_available() ) {
+ $data = self::get_data( $posted_data );
+
+ if ( ! wc_gzd_dhl_wp_error_has_errors( $data['errors'] ) ) {
+ $dhl_order = new Order( $order );
+
+ if ( ! empty( $data['preferred_day'] ) ) {
+ $dhl_order->set_preferred_day( $data['preferred_day'] );
+ }
+
+ if ( 'place' === $data['preferred_location_type'] && ! empty( $data['preferred_location'] ) ) {
+ $dhl_order->set_preferred_location( $data['preferred_location'] );
+ } elseif ( 'neighbor' === $data['preferred_location_type'] && ! empty( $data['preferred_location_neighbor_name'] ) && ! empty( $data['preferred_location_neighbor_address'] ) ) {
+ $dhl_order->set_preferred_neighbor( $data['preferred_location_neighbor_name'] );
+ $dhl_order->set_preferred_neighbor_address( $data['preferred_location_neighbor_address'] );
+ }
+ }
+ }
+ }
+
+ public static function validate( $data, $errors ) {
+ $posted_data = $_POST;
+
+ if ( self::is_preferred_available() ) {
+ $data = self::get_data( $posted_data );
+
+ if ( wc_gzd_dhl_wp_error_has_errors( $data['errors'] ) ) {
+ foreach( $data['errors']->get_error_messages() as $message ) {
+ $errors->add( 'validation', $message );
+ }
+ }
+ }
+ }
+
+ /**
+ * @param \WC_Cart $cart
+ */
+ public static function add_fees( $cart ) {
+ if ( ! $_POST || ( is_admin() && ! is_ajax() ) ) {
+ return;
+ }
+
+ // POST information is either in a query string-like variable called 'post_data'...
+ if ( isset( $_POST['post_data'] ) ) {
+ parse_str( $_POST['post_data'], $post_data );
+ } else {
+ $post_data = $_POST;
+ }
+
+ if ( self::is_preferred_available( true ) ) {
+ $data = self::get_data( $post_data );
+
+ try {
+ if ( ! empty( $data['preferred_day'] ) ) {
+ if ( ! empty( $data['preferred_day_cost'] ) ) {
+ $cart->add_fee( _x( 'DHL Preferred Day', 'dhl', 'woocommerce-germanized' ), $data['preferred_day_cost'], true );
+ }
+ }
+ } catch ( Exception $e ) {}
+ }
+ }
+
+ public static function add_scripts() {
+
+ // load scripts on checkout page only
+ if ( ! is_checkout() ) {
+ return;
+ }
+
+ $deps = array( 'jquery', 'wc-checkout', 'jquery-tiptip' );
+ $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
+
+ wp_register_script( 'jquery-tiptip', WC()->plugin_url() . '/assets/js/jquery-tiptip/jquery.tipTip' . $suffix . '.js', array( 'jquery' ), WC_VERSION, true );
+ wp_register_script( 'wc-gzd-preferred-services-dhl', Package::get_assets_url() . '/js/preferred-services' . $suffix . '.js', $deps, Package::get_version(), true );
+ wp_register_style( 'wc-gzd-preferred-services-dhl', Package::get_assets_url() . '/css/preferred-services' . $suffix . '.css', array(), Package::get_version() );
+
+ $excluded_gateways = self::get_excluded_payment_gateways();
+
+ wp_localize_script( 'wc-gzd-preferred-services-dhl', 'wc_gzd_dhl_preferred_services_params', array(
+ 'ajax_url' => admin_url( 'admin-ajax.php' ),
+ 'payment_gateways_excluded' => empty( $excluded_gateways ) ? false : true,
+ ) );
+
+ wp_enqueue_script( 'wc-gzd-preferred-services-dhl' );
+ wp_enqueue_style( 'wc-gzd-preferred-services-dhl' );
+ }
+
+ protected static function get_excluded_payment_gateways() {
+ return (array) self::get_setting( 'payment_gateways_excluded' );
+ }
+ protected static function payment_gateway_supports_services( $method ) {
+ $methods = self::get_excluded_payment_gateways();
+
+ if ( ! empty( $methods ) && in_array( $method, $methods ) ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ protected static function get_preferred_day_cost() {
+ $cost = self::get_setting( 'PreferredDay_cost' );
+
+ if ( empty( $cost ) ) {
+ $cost = 0;
+ }
+
+ return $cost;
+ }
+
+ public static function is_preferred_day_excluded( $day ) {
+ if ( 'yes' === self::get_setting( 'PreferredDay_exclusion_' . $day ) ) {
+ return true;
+ }
+
+ return false;
+ }
+
+ public static function get_preferred_day_cutoff_time() {
+ $time = self::get_setting( 'PreferredDay_cutoff_time' );
+
+ return $time;
+ }
+
+ public static function get_preferred_day_preparation_days() {
+ $days = self::get_setting( 'PreferredDay_preparation_days' );
+
+ if ( empty( $days ) || $days < 0 ) {
+ $days = 0;
+ }
+
+ return $days;
+ }
+
+ protected static function is_preferred_enabled() {
+ return self::is_preferred_day_enabled() || self::is_preferred_location_enabled() || self::is_preferred_neighbor_enabled();
+ }
+
+ protected static function is_preferred_available( $check_day_transfer = false ) {
+ $customer_country = WC()->customer->get_shipping_country();
+ $chosen_payment_method = (array) WC()->session->get( 'chosen_payment_method' );
+ $display_preferred = false;
+
+ // Preferred options are only for Germany customers
+ if ( self::is_enabled() && 'DE' === $customer_country ) {
+
+ if ( self::is_preferred_enabled() ) {
+ $display_preferred = true;
+ }
+
+ foreach( $chosen_payment_method as $key => $method ) {
+ if ( ! self::payment_gateway_supports_services( $method ) ) {
+ $display_preferred = false;
+ break;
+ }
+ }
+ }
+
+ return $display_preferred;
+ }
+
+ protected static function get_data( $post_data ) {
+ $data = array(
+ 'preferred_day_enabled' => false,
+ 'preferred_location_enabled' => false,
+ 'preferred_neighbor_enabled' => false,
+ 'preferred_day' => '',
+ 'preferred_location_type' => 'none',
+ 'preferred_location' => '',
+ 'preferred_location_neighbor_name' => '',
+ 'preferred_location_neighbor_address' => '',
+ 'preferred_day_options' => WC()->session->get( 'dhl_preferred_day_options' ),
+ 'preferred_day_cost' => self::get_preferred_day_cost(),
+ );
+
+ $data['errors'] = new WP_Error();
+
+ if ( is_null( $data['preferred_day_options'] ) ) {
+ self::refresh_day_session();
+ $data['preferred_day_options'] = WC()->session->get( 'dhl_preferred_day_options' );
+ }
+
+ try {
+ if ( self::is_preferred_day_enabled() ) {
+ $data['preferred_day_enabled'] = true;
+
+ if ( isset( $post_data['dhl_preferred_day'] ) && ! empty( $post_data['dhl_preferred_day'] ) ) {
+ $day = wc_clean( $post_data['dhl_preferred_day'] );
+
+ if ( wc_gzd_dhl_is_valid_datetime( $day, 'Y-m-d' ) ) {
+ if ( ! empty( $data['preferred_day_options'] ) ) {
+ if ( array_key_exists( $day, $data['preferred_day_options'] ) ) {
+ $data['preferred_day'] = $day;
+ }
+ }
+ }
+
+ if ( empty( $data['preferred_day'] ) ) {
+ $data['errors']->add( 'validation', _x( 'Sorry, but the preferred day you have chosen is no longer available.', 'dhl', 'woocommerce-germanized' ) );
+ }
+ }
+ }
+
+ if ( self::is_preferred_neighbor_enabled() ) {
+ $data['preferred_neighbor_enabled'] = true;
+ }
+
+ if ( self::is_preferred_location_enabled() ) {
+ $data['preferred_location_enabled'] = true;
+ }
+
+ if ( self::is_preferred_location_enabled() || self::is_preferred_neighbor_enabled() ) {
+ if ( isset( $post_data['dhl_preferred_location_type'] ) && 'none' !== $post_data['dhl_preferred_location_type'] ) {
+ if ( self::is_preferred_location_enabled() && 'place' === $post_data['dhl_preferred_location_type'] ) {
+ $location = isset( $post_data['dhl_preferred_location'] ) ? wc_clean( $post_data['dhl_preferred_location'] ) : '';
+
+ $data['preferred_location_type'] = 'place';
+
+ if ( ! empty( $location ) ) {
+ $data['preferred_location'] = $location;
+ } else {
+ $data['errors']->add( 'validation', _x( 'Please choose a preferred location.', 'dhl', 'woocommerce-germanized' ) );
+ }
+ } elseif( self::is_preferred_neighbor_enabled() && 'neighbor' === $post_data['dhl_preferred_location_type'] ) {
+ $name = isset( $post_data['dhl_preferred_location_neighbor_name'] ) ? wc_clean( $post_data['dhl_preferred_location_neighbor_name'] ) : '';
+ $address = isset( $post_data['dhl_preferred_location_neighbor_address'] ) ? wc_clean( $post_data['dhl_preferred_location_neighbor_address'] ) : '';
+
+ $data['preferred_location_type'] = 'neighbor';
+
+ if ( ! empty( $name ) && ! empty( $address ) ) {
+ $data['preferred_location_neighbor_name'] = $name;
+ $data['preferred_location_neighbor_address'] = $address;
+ } else {
+ $data['errors']->add( 'validation', _x( 'Please choose name and address of your preferred neighbor.', 'dhl', 'woocommerce-germanized' ) );
+ }
+ }
+ }
+ }
+
+ return $data;
+ } catch( Exception $e ) {
+ return $data;
+ }
+ }
+
+ protected static function refresh_day_session() {
+ WC()->session->set( 'dhl_preferred_day_options', array() );
+
+ if ( self::is_preferred_day_enabled() ) {
+ $shipping_postcode = WC()->customer->get_shipping_postcode();
+
+ try {
+ if ( ! empty( $shipping_postcode ) ) {
+ WC()->session->set( 'dhl_preferred_day_options', Package::get_api()->get_preferred_available_days( $shipping_postcode ) );
+ }
+ } catch( Exception $e ) {}
+ }
+ }
+
+ public static function add_fields() {
+ $post_data = array();
+
+ if ( isset( $_POST['post_data'] ) ) {
+ parse_str( $_POST['post_data'], $post_data );
+ }
+
+ if ( self::is_preferred_available( true ) ) {
+ $data = self::get_data( $post_data );
+
+ self::refresh_day_session();
+
+ $data['preferred_day_options'] = WC()->session->get( 'dhl_preferred_day_options' );
+ $data['logo_url'] = Package::get_assets_url() . '/img/dhl-official.png';
+
+ wc_get_template( 'checkout/dhl/preferred-services.php', $data, Package::get_template_path(), Package::get_path() . '/templates/' );
+ }
+ }
+
+ public static function is_enabled() {
+ return Package::base_country_supports( 'services' );
+ }
+
+ public static function is_preferred_day_enabled() {
+ return wc_string_to_bool( self::get_setting( 'PreferredDay_enable' ) );
+ }
+
+ public static function is_preferred_time_enabled() {
+ return wc_string_to_bool( self::get_setting( 'PreferredTime_enable' ) );
+ }
+
+ public static function is_preferred_location_enabled() {
+ return wc_string_to_bool( self::get_setting( 'PreferredLocation_enable' ) );
+ }
+
+ public static function is_preferred_neighbor_enabled() {
+ return wc_string_to_bool( self::get_setting( 'PreferredNeighbour_enable' ) );
+ }
+
+ protected static function get_setting( $key ) {
+
+ if ( strpos( $key, 'Preferred' ) === false ) {
+ $key = 'preferred_' . $key;
+ }
+
+ if ( $method = wc_gzd_dhl_get_current_shipping_method() ) {
+ if ( $method->has_option( $key ) ) {
+ return $method->get_option( $key );
+ } elseif( strpos( $key, '_enable' ) !== false ) {
+ return false;
+ }
+ }
+
+ $setting = Package::get_setting( $key );
+
+ return $setting;
+ }
+}
diff --git a/packages/woocommerce-germanized-dhl/src/Product.php b/packages/woocommerce-germanized-dhl/src/Product.php
new file mode 100644
index 000000000..f48795e64
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/Product.php
@@ -0,0 +1,100 @@
+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' ) ) {
+ return wc_get_product( $this->product->get_parent_id() );
+ }
+
+ return $this->product;
+ }
+
+ public function get_hs_code() {
+ return $this->get_forced_parent_product()->get_meta( '_dhl_hs_code', true );
+ }
+
+ public function get_manufacture_country() {
+ return $this->get_forced_parent_product()->get_meta( '_dhl_manufacture_country', true );
+ }
+
+ 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( '_dhl_hs_code', $code );
+ }
+
+ public function set_manufacture_country( $country ) {
+ $this->product->update_meta_data( '_dhl_manufacture_country', $country );
+ }
+
+ /**
+ * 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-dhl/src/ShippingProvider/DHL.php b/packages/woocommerce-germanized-dhl/src/ShippingProvider/DHL.php
new file mode 100644
index 000000000..e35ec63d1
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/ShippingProvider/DHL.php
@@ -0,0 +1,1709 @@
+get_meta( 'sandbox_mode', true );
+ }
+
+ public function get_customer_number() {
+ return $this->get_meta( 'account_number', true );
+ }
+
+ public function get_label_classname( $type ) {
+ if ( 'return' === $type ) {
+ return '\Vendidero\Germanized\DHL\Label\DHLReturn';
+ } elseif ( 'inlay_return' === $type ) {
+ return '\Vendidero\Germanized\DHL\Label\DHLInlayReturn';
+ } else {
+ return '\Vendidero\Germanized\DHL\Label\DHL';
+ }
+ }
+
+ public function supports_labels( $label_type, $shipment = false ) {
+ $label_types = array( 'simple' );
+
+ if ( $this->enable_retoure() ) {
+ $label_types[] = 'return';
+ }
+
+ return in_array( $label_type, $label_types );
+ }
+
+ public function supports_customer_return_requests() {
+ return $this->enable_retoure();
+ }
+
+ /**
+ * 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_api_username( $context = 'view' ) {
+ return $this->get_meta( 'api_username', true, $context );
+ }
+
+ public function set_api_username( $username ) {
+ $this->update_meta_data( 'api_username', strtolower( $username ) );
+ }
+
+ public function get_label_retoure_enable( $context = 'view' ) {
+ return wc_string_to_bool( $this->get_meta( 'label_retoure_enable', true, $context ) );
+ }
+
+ public function set_label_retoure_enable( $enable ) {
+ $this->update_meta_data( 'label_retoure_enable', wc_bool_to_string( $enable ) );
+ }
+
+ public function get_retoure_receiver_ids( $context = 'view' ) {
+ $ids = (array) $this->get_meta( 'retoure_receiver_ids', true, $context );
+
+ return array_filter( $ids );
+ }
+
+ public function set_retoure_receiver_ids( $ids ) {
+ $this->update_meta_data( 'retoure_receiver_ids', array_filter( (array) $ids ) );
+ }
+
+ public function get_api_sandbox_username( $context = 'view' ) {
+ return $this->get_meta( 'api_sandbox_username', true, $context );
+ }
+
+ public function set_api_sandbox_username( $username ) {
+ $this->update_meta_data( 'api_sandbox_username', strtolower( $username ) );
+ }
+
+ public function get_setting_sections() {
+ $sections = parent::get_setting_sections();
+
+ $sections['pickup'] = _x( 'Parcel Pickup', 'dhl', 'woocommerce-germanized' );
+ $sections['preferred'] = _x( 'Preferred Services', 'dhl', 'woocommerce-germanized' );
+
+ return $sections;
+ }
+
+ /**
+ * @param \Vendidero\Germanized\Shipments\Shipment $shipment
+ *
+ * @return array
+ */
+ protected function get_return_label_fields( $shipment ) {
+ $default_args = $this->get_default_label_props( $shipment );
+
+ return array(
+ array(
+ 'id' => 'receiver_slug',
+ 'label' => _x( 'Receiver', 'dhl', 'woocommerce-germanized' ),
+ 'description' => '',
+ 'type' => 'select',
+ 'options' => wc_gzd_dhl_get_return_receivers(),
+ 'value' => isset( $default_args['receiver_slug'] ) ? $default_args['receiver_slug'] : '',
+ )
+ );
+ }
+
+ /**
+ * @param \Vendidero\Germanized\Shipments\Shipment $shipment
+ *
+ * @return array
+ */
+ protected function get_simple_label_fields( $shipment ) {
+ $settings = parent::get_simple_label_fields( $shipment );
+ $dhl_order = wc_gzd_dhl_get_order( $shipment->get_order() );
+ $default_args = $this->get_default_label_props( $shipment );
+
+ if ( $dhl_order->has_cod_payment() ) {
+ $settings = array_merge( $settings, array(
+ array(
+ 'id' => 'cod_total',
+ 'class' => 'wc_input_decimal',
+ 'label' => _x( 'COD Amount', 'dhl', 'woocommerce-germanized' ),
+ 'placeholder' => '',
+ 'description' => '',
+ 'value' => isset( $default_args['cod_total'] ) ? $default_args['cod_total'] : '',
+ 'type' => 'text'
+ )
+ ) );
+ }
+
+ if ( Package::is_crossborder_shipment( $shipment->get_country() ) ) {
+ $settings = array_merge( $settings, array(
+ array(
+ 'id' => 'duties',
+ 'label' => _x( 'Duties', 'dhl', 'woocommerce-germanized' ),
+ 'description' => '',
+ 'value' => isset( $default_args['duties'] ) ? $default_args['duties'] : '',
+ 'options' => wc_gzd_dhl_get_duties(),
+ 'type' => 'select'
+ )
+ ) );
+ }
+
+ $settings = array_merge( $settings, array(
+ array(
+ 'id' => 'codeable_address_only',
+ 'label' => _x( 'Valid address only', 'dhl', 'woocommerce-germanized' ),
+ 'placeholder' => '',
+ 'description' => '',
+ 'type' => 'checkbox',
+ 'value' => isset( $default_args['codeable_address_only'] ) ? wc_bool_to_string( $default_args['codeable_address_only'] ) : 'no',
+ 'wrapper_class' => 'form-field-checkbox'
+ ),
+ ) );
+
+ $services = array(
+ array(
+ 'id' => 'service_GoGreen',
+ 'label' => _x( 'GoGreen', 'dhl', 'woocommerce-germanized' ),
+ 'description' => '',
+ 'type' => 'checkbox',
+ 'value' => in_array( 'GoGreen', $default_args['services'] ) ? 'yes' : 'no',
+ 'wrapper_class' => 'form-field-checkbox',
+ 'custom_attributes' => wc_gzd_dhl_get_service_product_attributes( 'GoGreen' )
+ ),
+ array(
+ 'id' => 'service_AdditionalInsurance',
+ 'label' => _x( 'Additional insurance', 'dhl', 'woocommerce-germanized' ),
+ 'description' => '',
+ 'type' => 'checkbox',
+ 'value' => in_array( 'AdditionalInsurance', $default_args['services'] ) ? 'yes' : 'no',
+ 'wrapper_class' => 'form-field-checkbox',
+ 'custom_attributes' => wc_gzd_dhl_get_service_product_attributes( 'AdditionalInsurance' )
+ )
+ );
+
+ if ( Package::is_shipping_domestic( $shipment->get_country() ) ) {
+ $preferred_days = array();
+
+ try {
+ $preferred_day_options = Package::get_api()->get_preferred_available_days( $shipment->get_postcode() );
+
+ if ( $preferred_day_options ) {
+ $preferred_days = $preferred_day_options;
+ }
+ } catch( \Exception $e ) {}
+
+ $settings = array_merge( $settings, array( array(
+ 'id' => 'preferred_day',
+ 'label' => _x( 'Preferred Day', 'dhl', 'woocommerce-germanized' ),
+ 'description' => '',
+ 'value' => isset( $default_args['preferred_day'] ) ? $default_args['preferred_day'] : '',
+ 'options' => wc_gzd_dhl_get_preferred_days_select_options( $preferred_days, ( isset( $default_args['preferred_day'] ) ? $default_args['preferred_day'] : '' ) ),
+ 'type' => 'select'
+ ) ) );
+
+ if ( $dhl_order->has_preferred_location() ) {
+ $settings = array_merge( $settings, array( array(
+ 'id' => 'preferred_location',
+ 'label' => _x( 'Preferred Location', 'dhl', 'woocommerce-germanized' ),
+ 'placeholder' => '',
+ 'description' => '',
+ 'value' => isset( $default_args['preferred_location'] ) ? $default_args['preferred_location'] : '',
+ 'custom_attributes' => array( 'maxlength' => '80' ),
+ 'type' => 'text'
+ ) ) );
+ }
+
+ if ( $dhl_order->has_preferred_neighbor() ) {
+ $settings = array_merge( $settings, array( array(
+ 'id' => 'preferred_neighbor',
+ 'label' => _x( 'Preferred Neighbor', 'dhl', 'woocommerce-germanized' ),
+ 'placeholder' => '',
+ 'description' => '',
+ 'value' => isset( $default_args['preferred_neighbor'] ) ? $default_args['preferred_neighbor'] : '',
+ 'custom_attributes' => array( 'maxlength' => '80' ),
+ 'type' => 'text'
+ ) ) );
+ }
+
+ $settings = array_merge( $settings, array(
+ array(
+ 'id' => 'has_inlay_return',
+ 'label' => _x( 'Create inlay return label', 'dhl', 'woocommerce-germanized' ),
+ 'class' => 'checkbox show-if-trigger',
+ 'custom_attributes' => array( 'data-show-if' => '.show-if-has-return' ),
+ 'desc_tip' => true,
+ 'value' => isset( $default_args['has_inlay_return'] ) ? wc_bool_to_string( $default_args['has_inlay_return'] ) : 'no',
+ 'wrapper_class' => 'form-field-checkbox',
+ 'type' => 'checkbox'
+ ),
+ array(
+ 'id' => 'return_address[name]',
+ 'label' => _x( 'Name', 'dhl', 'woocommerce-germanized' ),
+ 'placeholder' => '',
+ 'description' => '',
+ 'value' => isset( $default_args['return_address']['name'] ) ? $default_args['return_address']['name'] : '',
+ 'type' => 'text',
+ 'wrapper_class' => 'show-if-has-return',
+ ),
+ array(
+ 'id' => 'return_address[company]',
+ 'label' => _x( 'Company', 'dhl', 'woocommerce-germanized' ),
+ 'placeholder' => '',
+ 'description' => '',
+ 'wrapper_class' => 'show-if-has-return',
+ 'type' => 'text',
+ 'value' => isset( $default_args['return_address']['company'] ) ? $default_args['return_address']['company'] : '',
+ ),
+ array(
+ 'id' => '',
+ 'type' => 'columns',
+ ),
+ array(
+ 'id' => 'return_address[street]',
+ 'label' => _x( 'Street', 'dhl', 'woocommerce-germanized' ),
+ 'placeholder' => '',
+ 'description' => '',
+ 'type' => 'text',
+ 'wrapper_class' => 'show-if-has-return column col-9',
+ 'value' => isset( $default_args['return_address']['street'] ) ? $default_args['return_address']['street'] : '',
+ ),
+ array(
+ 'id' => 'return_address[street_number]',
+ 'label' => _x( 'Street No', 'dhl', 'woocommerce-germanized' ),
+ 'placeholder' => '',
+ 'description' => '',
+ 'type' => 'text',
+ 'wrapper_class' => 'show-if-has-return column col-3',
+ 'value' => isset( $default_args['return_address']['street_number'] ) ? $default_args['return_address']['street_number'] : '',
+ ),
+ array(
+ 'id' => '',
+ 'type' => 'columns',
+ ),
+ array(
+ 'id' => 'return_address[postcode]',
+ 'label' => _x( 'Postcode', 'dhl', 'woocommerce-germanized' ),
+ 'placeholder' => '',
+ 'description' => '',
+ 'type' => 'text',
+ 'wrapper_class' => 'show-if-has-return column col-6',
+ 'value' => isset( $default_args['return_address']['postcode'] ) ? $default_args['return_address']['postcode'] : '',
+ ),
+ array(
+ 'id' => 'return_address[city]',
+ 'label' => _x( 'City', 'dhl', 'woocommerce-germanized' ),
+ 'placeholder' => '',
+ 'description' => '',
+ 'type' => 'text',
+ 'wrapper_class' => 'show-if-has-return column col-6',
+ 'value' => isset( $default_args['return_address']['city'] ) ? $default_args['return_address']['city'] : '',
+ ),
+ array(
+ 'id' => '',
+ 'type' => 'columns',
+ ),
+ array(
+ 'id' => 'return_address[phone]',
+ 'label' => _x( 'Phone', 'dhl', 'woocommerce-germanized' ),
+ 'placeholder' => '',
+ 'description' => '',
+ 'type' => 'text',
+ 'wrapper_class' => 'show-if-has-return column col-6',
+ 'value' => isset( $default_args['return_address']['phone'] ) ? $default_args['return_address']['phone'] : '',
+ ),
+ array(
+ 'id' => 'return_address[email]',
+ 'label' => _x( 'Email', 'dhl', 'woocommerce-germanized' ),
+ 'placeholder' => '',
+ 'description' => '',
+ 'type' => 'text',
+ 'wrapper_class' => 'show-if-has-return column col-6',
+ 'value' => isset( $default_args['return_address']['email'] ) ? $default_args['return_address']['email'] : '',
+ ),
+ array(
+ 'id' => '',
+ 'type' => 'columns_end',
+ ),
+ ) );
+
+ $services = array_merge( $services, array(
+ array(
+ 'id' => 'visual_min_age',
+ 'label' => _x( 'Age check', 'dhl', 'woocommerce-germanized' ),
+ 'description' => '',
+ 'type' => 'select',
+ 'value' => isset( $default_args['visual_min_age'] ) ? $default_args['visual_min_age'] : '',
+ 'options' => wc_gzd_dhl_get_visual_min_ages(),
+ 'custom_attributes' => wc_gzd_dhl_get_service_product_attributes( 'VisualCheckOfAge' )
+ ),
+ ) );
+
+ if ( $dhl_order->supports_email_notification() ) {
+ $services = array_merge( $services, array(
+ array(
+ 'id' => 'service_ParcelOutletRouting',
+ 'label' => _x( 'Retail outlet routing', 'dhl', 'woocommerce-germanized' ),
+ 'description' => '',
+ 'type' => 'checkbox',
+ 'value' => in_array( 'ParcelOutletRouting', $default_args['services'] ) ? 'yes' : 'no',
+ 'wrapper_class' => 'form-field-checkbox',
+ 'custom_attributes' => wc_gzd_dhl_get_service_product_attributes( 'ParcelOutletRouting' )
+ )
+ ) );
+ }
+
+ if ( ! $dhl_order->has_preferred_neighbor() ) {
+ $services = array_merge( $services, array(
+ array(
+ 'id' => 'service_NoNeighbourDelivery',
+ 'label' => _x( 'No neighbor', 'dhl', 'woocommerce-germanized' ),
+ 'description' => '',
+ 'type' => 'checkbox',
+ 'value' => in_array( 'NoNeighbourDelivery', $default_args['services'] ) ? 'yes' : 'no',
+ 'wrapper_class' => 'form-field-checkbox',
+ 'custom_attributes' => wc_gzd_dhl_get_service_product_attributes( 'NoNeighbourDelivery' )
+ )
+ ) );
+ }
+
+ $services = array_merge( $services, array(
+ array(
+ 'id' => 'service_NamedPersonOnly',
+ 'label' => _x( 'Named person only', 'dhl', 'woocommerce-germanized' ),
+ 'description' => '',
+ 'type' => 'checkbox',
+ 'value' => in_array( 'NamedPersonOnly', $default_args['services'] ) ? 'yes' : 'no',
+ 'wrapper_class' => 'form-field-checkbox',
+ 'custom_attributes' => wc_gzd_dhl_get_service_product_attributes( 'NamedPersonOnly' )
+ ),
+ array(
+ 'id' => 'service_BulkyGoods',
+ 'label' => _x( 'Bulky goods', 'dhl', 'woocommerce-germanized' ),
+ 'description' => '',
+ 'type' => 'checkbox',
+ 'value' => in_array( 'BulkyGoods', $default_args['services'] ) ? 'yes' : 'no',
+ 'wrapper_class' => 'form-field-checkbox',
+ 'custom_attributes' => wc_gzd_dhl_get_service_product_attributes( 'BulkyGoods' )
+ ),
+ array(
+ 'id' => 'service_IdentCheck',
+ 'label' => _x( 'Identity check', 'dhl', 'woocommerce-germanized' ),
+ 'description' => '',
+ 'type' => 'checkbox',
+ 'class' => 'checkbox show-if-trigger',
+ 'value' => in_array( 'IdentCheck', $default_args['services'] ) ? 'yes' : 'no',
+ 'custom_attributes' => array_merge( array( 'data-show-if' => '.show-if-ident-check' ), wc_gzd_dhl_get_service_product_attributes( 'IdentCheck' ) ),
+ 'wrapper_class' => 'form-field-checkbox',
+ ),
+ array(
+ 'id' => '',
+ 'type' => 'columns',
+ ),
+ array(
+ 'id' => 'ident_date_of_birth',
+ 'label' => _x( 'Date of Birth', 'dhl', 'woocommerce-germanized' ),
+ 'placeholder' => '',
+ 'description' => '',
+ 'value' => isset( $default_args['ident_date_of_birth'] ) ? $default_args['ident_date_of_birth'] : '',
+ 'custom_attributes' => array( 'pattern' => '[0-9]{4}-(0[1-9]|1[012])-(0[1-9]|1[0-9]|2[0-9]|3[01])', 'maxlength' => 10 ),
+ 'class' => 'short date-picker',
+ 'wrapper_class' => 'show-if-ident-check column col-6',
+ 'type' => 'text',
+ ),
+ array(
+ 'id' => 'ident_min_age',
+ 'label' => _x( 'Minimum age', 'dhl', 'woocommerce-germanized' ),
+ 'description' => '',
+ 'wrapper_class' => 'show-if-ident-check column col-6',
+ 'type' => 'select',
+ 'value' => isset( $default_args['ident_min_age'] ) ? $default_args['ident_min_age'] : '',
+ 'options' => wc_gzd_dhl_get_ident_min_ages(),
+ ),
+ array(
+ 'id' => '',
+ 'type' => 'columns_end',
+ ),
+ ) );
+ } elseif( Package::is_crossborder_shipment( $shipment->get_country() ) ) {
+ $services = array_merge( $services, array(
+ array(
+ 'id' => 'service_Premium',
+ 'label' => _x( 'Premium', 'dhl', 'woocommerce-germanized' ),
+ 'description' => '',
+ 'value' => in_array( 'Premium', $default_args['services'] ) ? 'yes' : 'no',
+ 'wrapper_class' => 'form-field-checkbox',
+ 'type' => 'checkbox',
+ 'custom_attributes' => wc_gzd_dhl_get_service_product_attributes( 'Premium' )
+ )
+ ) );
+ }
+
+ $settings[] = array(
+ 'type' => 'services_start',
+ 'id' => '',
+ );
+
+ $settings = array_merge( $settings, $services );
+
+ return $settings;
+ }
+
+ public function get_participation_number( $product ) {
+ return $this->get_setting( 'participation_' . $product, '' );
+ }
+
+ public function enable_retoure() {
+ return $this->get_label_retoure_enable();
+ }
+
+ /**
+ * @param Shipment $shipment
+ * @param $props
+ *
+ * @return \WP_Error|mixed
+ */
+ protected function validate_label_request( $shipment, $props ) {
+ if ( 'return' === $shipment->get_type() ) {
+ $props = $this->validate_return_label_args( $shipment, $props );
+ } else {
+ $props = $this->validate_simple_label_args( $shipment, $props );
+ }
+
+ return $props;
+ }
+
+ /**
+ * @param Shipment $shipment
+ * @param $args
+ *
+ * @return \WP_Error|mixed
+ */
+ protected function validate_return_label_args( $shipment, $args = array() ) {
+ $args = wp_parse_args( $args, array(
+ 'receiver_slug' => '',
+ ) );
+
+ $error = new \WP_Error();
+
+ $args['receiver_slug'] = sanitize_key( $args['receiver_slug'] );
+
+ if ( empty( $args['receiver_slug'] ) ) {
+ $error->add( 500, _x( 'Receiver is missing or does not exist.', 'dhl', 'woocommerce-germanized' ) );
+ }
+
+ if ( wc_gzd_dhl_wp_error_has_errors( $error ) ) {
+ return $error;
+ }
+
+ return $args;
+ }
+
+ /**
+ * @param Shipment $shipment
+ * @param $args
+ *
+ * @return \WP_Error|mixed
+ */
+ protected function validate_simple_label_args( $shipment, $args = array() ) {
+ $args = wp_parse_args( $args, array(
+ 'preferred_day' => '',
+ 'preferred_location' => '',
+ 'preferred_neighbor' => '',
+ 'ident_date_of_birth' => '',
+ 'ident_min_age' => '',
+ 'visual_min_age' => '',
+ 'has_inlay_return' => 'no',
+ 'cod_total' => 0,
+ 'product_id' => '',
+ 'duties' => '',
+ 'services' => array(),
+ 'return_address' => array(),
+ ) );
+
+ $error = new \WP_Error();
+ $dhl_order = wc_gzd_dhl_get_order( $shipment->get_order() );
+
+ // Do only allow valid services
+ if ( ! empty( $args['services'] ) ) {
+ $args['services'] = array_intersect( $args['services'], wc_gzd_dhl_get_services() );
+
+ foreach( $args['services'] as $key => $service ) {
+ /**
+ * Remove services that are not supported for this product
+ */
+ if ( ! wc_gzd_dhl_product_supports_service( $args['product_id'], $service ) ) {
+ unset( $args['services'][ $key ] );
+ }
+ }
+
+ $args['services'] = array_values( $args['services'] );
+ }
+
+ // Check if return address has empty mandatory fields
+ if ( 'yes' === $args['has_inlay_return'] ) {
+ $args['return_address'] = wp_parse_args( $args['return_address'], array(
+ 'name' => '',
+ 'company' => '',
+ 'street' => '',
+ 'street_number' => '',
+ 'postcode' => '',
+ 'city' => '',
+ 'state' => '',
+ 'country' => Package::get_setting( 'return_country' ),
+ ) );
+
+ $mandatory = array(
+ 'street' => _x( 'Street', 'dhl', 'woocommerce-germanized' ),
+ 'postcode' => _x( 'Postcode', 'dhl', 'woocommerce-germanized' ),
+ 'city' => _x( 'City', 'dhl', 'woocommerce-germanized' ),
+ );
+
+ foreach( $mandatory as $mand => $title ) {
+ if ( empty( $args['return_address'][ $mand ] ) ) {
+ $error->add( 500, sprintf( _x( '%s of the return address is a mandatory field.', 'dhl', 'woocommerce-germanized' ), $title ) );
+ }
+ }
+
+ if ( empty( $args['return_address']['name'] ) && empty( $args['return_address']['company'] ) ) {
+ $error->add( 500, _x( 'Please either add a return company or name.', 'dhl', 'woocommerce-germanized' ) );
+ }
+ } else {
+ unset( $args['return_address'] );
+ unset( $args['has_inlay_return'] );
+ }
+
+ // No cash on delivery available
+ if ( ( $dhl_order && ! empty( $args['cod_total'] ) && ! $dhl_order->has_cod_payment() ) || empty( $args['cod_total'] ) ) {
+ unset( $args['cod_total'] );
+ }
+
+ if ( $dhl_order && ! empty( $args['cod_total'] ) && $dhl_order->has_cod_payment() && wc_gzd_dhl_product_supports_service( $args['product_id'], 'CashOnDelivery' ) ) {
+ $args['services'] = array_merge( $args['services'], array( 'CashOnDelivery' ) );
+ }
+
+ if ( ! empty( $args['preferred_day'] ) && wc_gzd_dhl_is_valid_datetime( $args['preferred_day'], 'Y-m-d' ) ) {
+ $args['services'] = array_merge( $args['services'], array( 'PreferredDay' ) );
+ } else {
+ if ( ! empty( $args['preferred_day'] ) && ! wc_gzd_dhl_is_valid_datetime( $args['preferred_day'], 'Y-m-d' ) ) {
+ $error->add( 500, _x( 'Error while parsing preferred day.', 'dhl', 'woocommerce-germanized' ) );
+ }
+
+ $args['services'] = array_diff( $args['services'], array( 'PreferredDay' ) );
+
+ unset( $args['preferred_day'] );
+ }
+
+ if ( ! empty( $args['preferred_location'] ) ) {
+ $args['services'] = array_merge( $args['services'], array( 'PreferredLocation' ) );
+ } else {
+ $args['services'] = array_diff( $args['services'], array( 'PreferredLocation' ) );
+ unset( $args['preferred_location'] );
+ }
+
+ if ( ! empty( $args['preferred_neighbor'] ) ) {
+ $args['services'] = array_merge( $args['services'], array( 'PreferredNeighbour' ) );
+ } else {
+ $args['services'] = array_diff( $args['services'], array( 'PreferredNeighbour' ) );
+ unset( $args['preferred_neighbor'] );
+ }
+
+ if ( wc_gzd_dhl_product_supports_service( $args['product_id'], 'VisualCheckOfAge' ) ) {
+ if ( ! empty( $args['visual_min_age'] ) && wc_gzd_dhl_is_valid_visual_min_age( $args['visual_min_age'] ) ) {
+ $args['services'] = array_merge( $args['services'], array( 'VisualCheckOfAge' ) );
+ } else {
+ if ( ! empty( $args['visual_min_age'] ) && ! wc_gzd_dhl_is_valid_visual_min_age( $args['visual_min_age'] ) ) {
+ $error->add( 500, _x( 'The visual min age check is invalid.', 'dhl', 'woocommerce-germanized' ) );
+ }
+
+ $args['services'] = array_diff( $args['services'], array( 'VisualCheckOfAge' ) );
+ unset( $args['visual_min_age'] );
+ }
+ } else {
+ unset( $args['visual_min_age'] );
+ }
+
+ // In case order does not support email notification - remove parcel outlet routing
+ if ( in_array( 'ParcelOutletRouting', $args['services'] ) ) {
+ if ( ! $dhl_order || ! $dhl_order->supports_email_notification() ) {
+ $args['services'] = array_diff( $args['services'], array( 'ParcelOutletRouting' ) );
+ }
+ }
+
+ if ( wc_gzd_dhl_product_supports_service( $args['product_id'], 'IdentCheck' ) ) {
+ if ( ! empty( $args['ident_min_age'] ) && wc_gzd_dhl_is_valid_ident_min_age( $args['ident_min_age'] ) ) {
+ $args['services'] = array_merge( $args['services'], array( 'IdentCheck' ) );
+ }
+
+ if ( in_array( 'IdentCheck', $args['services'] ) ) {
+ if ( ! empty( $args['ident_min_age'] ) && ! array_key_exists( $args['ident_min_age'], wc_gzd_dhl_get_ident_min_ages() ) ) {
+ $error->add( 500, _x( 'The ident min age check is invalid.', 'dhl', 'woocommerce-germanized' ) );
+ }
+
+ if ( ! empty( $args['ident_date_of_birth'] ) ) {
+ if ( ! wc_gzd_dhl_is_valid_datetime( $args['ident_date_of_birth'], 'Y-m-d' ) ) {
+ $error->add( 500, _x( 'There was an error parsing the date of birth for the identity check.', 'dhl', 'woocommerce-germanized' ) );
+ }
+ }
+
+ if ( empty( $args['ident_date_of_birth'] ) && empty( $args['ident_min_age'] ) ) {
+ $error->add( 500, _x( 'Either a minimum age or a date of birth must be added to the ident check.', 'dhl', 'woocommerce-germanized' ) );
+ }
+ } else {
+ unset( $args['ident_min_age'] );
+ unset( $args['ident_date_of_birth'] );
+ }
+ } else {
+ unset( $args['ident_min_age'] );
+ unset( $args['ident_date_of_birth'] );
+ }
+
+ // We don't need duties for non-cross-border shipments
+ if ( ! Package::is_crossborder_shipment( $shipment->get_country() ) ) {
+ unset( $args['duties'] );
+ }
+
+ if ( ! empty( $args['duties'] ) && ! array_key_exists( $args['duties'], wc_gzd_dhl_get_duties() ) ) {
+ $error->add( 500, sprintf( _x( '%s duties element does not exist.', 'dhl', 'woocommerce-germanized' ), $args['duties'] ) );
+ }
+
+ if ( wc_gzd_dhl_wp_error_has_errors( $error ) ) {
+ return $error;
+ }
+
+ return $args;
+ }
+
+ /**
+ * @param Shipment $shipment
+ *
+ * @return array
+ */
+ protected function get_default_label_props( $shipment ) {
+ if ( 'return' === $shipment->get_type() ) {
+ $dhl_defaults = $this->get_default_return_label_props( $shipment );
+ } else {
+ $dhl_defaults = $this->get_default_simple_label_props( $shipment );
+ }
+
+ $defaults = parent::get_default_label_props( $shipment );
+
+ return array_replace_recursive( $defaults, $dhl_defaults );
+ }
+
+ /**
+ * @param Shipment $shipment
+ *
+ * @return array
+ */
+ protected function get_default_return_label_props( $shipment ) {
+ $defaults = array(
+ 'services' => array(),
+ 'receiver_slug' => wc_gzd_dhl_get_default_return_receiver_slug( $shipment->get_sender_country() ),
+ 'sender_address' => $shipment->get_sender_address(),
+ );
+
+ $defaults['sender_address'] = array_merge( $defaults['sender_address'], array(
+ 'name' => $shipment->get_formatted_sender_full_name(),
+ 'street' => $shipment->get_sender_address_street(),
+ 'street_number' => $shipment->get_sender_address_street_number(),
+ 'street_addition' => $shipment->get_sender_address_street_addition(),
+ ) );
+
+ return $defaults;
+ }
+
+ /**
+ * @param \Vendidero\Germanized\Shipments\Shipment $shipment
+ */
+ public function get_default_label_product( $shipment ) {
+ if ( 'simple' === $shipment->get_type() ) {
+ if ( Package::is_shipping_domestic( $shipment->get_country() ) ) {
+ return $this->get_shipment_setting( $shipment, 'label_default_product_dom' );
+ } else {
+ return $this->get_shipment_setting( $shipment, 'label_default_product_int' );
+ }
+ }
+
+ return '';
+ }
+
+ /**
+ * @param Shipment $shipment
+ *
+ * @return array
+ */
+ protected function get_default_simple_label_props( $shipment ) {
+ $dhl_order = wc_gzd_dhl_get_order( $shipment->get_order() );
+ $product_id = $this->get_default_label_product( $shipment );
+
+ $defaults = array(
+ 'services' => array(),
+ 'codeable_address_only' => $this->get_shipment_setting( $shipment, 'label_address_codeable_only' ),
+ );
+
+ if ( $dhl_order && $dhl_order->supports_email_notification() ) {
+ $defaults['email_notification'] = 'yes';
+ }
+
+ if ( $dhl_order && $dhl_order->has_cod_payment() && wc_gzd_dhl_product_supports_service( $product_id, 'CashOnDelivery' ) ) {
+ $defaults['cod_total'] = $shipment->get_total();
+
+ /**
+ * This check is necessary to make sure only one label per order
+ * has the additional total (shipping total, fee total) added to the COD amount.
+ */
+ $shipments = wc_gzd_get_shipments_by_order( $shipment->get_order_id() );
+ $needs_additional_total = true;
+
+ foreach( $shipments as $shipment ) {
+ if ( $existing_label = wc_gzd_dhl_get_shipment_label( $shipment, 'simple' ) ) {
+
+ if ( $existing_label->cod_includes_additional_total() ) {
+ $needs_additional_total = false;
+ break;
+ }
+ }
+ }
+
+ if ( $needs_additional_total ) {
+ $defaults['cod_total'] += round( $shipment->get_additional_total(), wc_get_price_decimals() );
+ $defaults['cod_includes_additional_total'] = true;
+ }
+ }
+
+ if ( Package::is_crossborder_shipment( $shipment->get_country() ) ) {
+
+ $defaults['duties'] = $this->get_shipment_setting( $shipment, 'label_default_duty' );
+
+ } elseif ( Package::is_shipping_domestic( $shipment->get_country() ) ) {
+
+ if ( Package::base_country_supports( 'services' ) ) {
+
+ if ( $dhl_order && $dhl_order->has_preferred_day() ) {
+ $defaults['preferred_day'] = $dhl_order->get_preferred_day()->format( 'Y-m-d' );
+ }
+
+ if ( $dhl_order && $dhl_order->has_preferred_location() ) {
+ $defaults['preferred_location'] = $dhl_order->get_preferred_location();
+ }
+
+ if ( $dhl_order && $dhl_order->has_preferred_neighbor() ) {
+ $defaults['preferred_neighbor'] = $dhl_order->get_preferred_neighbor_formatted_address();
+ }
+
+ if ( wc_gzd_dhl_product_supports_service( $product_id, 'VisualCheckOfAge' ) ) {
+ $visual_min_age = $this->get_shipment_setting( $shipment, 'label_visual_min_age' );
+
+ if ( wc_gzd_dhl_is_valid_visual_min_age( $visual_min_age ) ) {
+ $defaults['services'][] = 'VisualCheckOfAge';
+ $defaults['visual_min_age'] = $visual_min_age;
+ }
+
+ if ( $dhl_order->needs_age_verification() && 'yes' === $this->get_shipment_setting( $shipment, 'label_auto_age_check_sync' ) ) {
+ $defaults['services'][] = 'VisualCheckOfAge';
+ $defaults['visual_min_age'] = $dhl_order->get_min_age();
+ }
+ }
+
+ if ( wc_gzd_dhl_product_supports_service( $product_id, 'IdentCheck' ) ) {
+ $ident_min_age = $this->get_shipment_setting( $shipment, 'label_ident_min_age' );
+
+ if ( wc_gzd_dhl_is_valid_ident_min_age( $ident_min_age ) ) {
+ $defaults['services'][] = 'IdentCheck';
+ $defaults['ident_min_age'] = $ident_min_age;
+ }
+
+ /**
+ * Sync with order data but only in case no visual age has been synced already.
+ */
+ if ( ! in_array( 'VisualCheckOfAge', $defaults['services'] ) ) {
+ if ( $dhl_order && $dhl_order->needs_age_verification() && 'yes' === $this->get_shipment_setting( $shipment, 'label_auto_age_check_ident_sync' ) ) {
+ $defaults['services'][] = 'IdentCheck';
+ $defaults['ident_min_age'] = $dhl_order->get_min_age();
+ }
+ }
+ }
+
+ foreach( wc_gzd_dhl_get_services() as $service ) {
+ if ( ! wc_gzd_dhl_product_supports_service( $product_id, $service ) ) {
+ continue;
+ }
+
+ // Combination is not available
+ if ( ( ! empty( $defaults['visual_min_age'] ) || ! empty( $defaults['ident_min_age'] ) ) && 'NamedPersonOnly' === $service ) {
+ continue;
+ }
+
+ if ( 'yes' === $this->get_shipment_setting( $shipment, 'label_service_' . $service ) ) {
+ $defaults['services'][] = $service;
+ }
+ }
+
+ // Demove duplicates
+ $defaults['services'] = array_unique( $defaults['services'] );
+ }
+
+ if ( Package::base_country_supports( 'returns' ) ) {
+
+ $defaults['return_address'] = array(
+ 'name' => Package::get_setting( 'return_name' ),
+ 'company' => Package::get_setting( 'return_company' ),
+ 'street' => Package::get_setting( 'return_street' ),
+ 'street_number' => Package::get_setting( 'return_street_number' ),
+ 'postcode' => Package::get_setting( 'return_postcode' ),
+ 'city' => Package::get_setting( 'return_city' ),
+ 'phone' => Package::get_setting( 'return_phone' ),
+ 'email' => Package::get_setting( 'return_email' ),
+ );
+
+ if ( 'yes' === $this->get_shipment_setting( $shipment, 'label_auto_inlay_return_label' ) ) {
+ $defaults['has_inlay_return'] = 'yes';
+ }
+ }
+ }
+
+ if ( ! Package::is_shipping_domestic( $shipment->get_country() ) ) {
+
+ foreach( wc_gzd_dhl_get_international_services() as $service ) {
+
+ if ( ! wc_gzd_dhl_product_supports_service( $product_id, $service ) ) {
+ continue;
+ }
+
+ if ( 'yes' === $this->get_shipment_setting( $shipment, 'label_service_' . $service ) ) {
+ $defaults['services'][] = $service;
+ }
+ }
+
+ // Demove duplicates
+ $defaults['services'] = array_unique( $defaults['services'] );
+ }
+
+ return $defaults;
+ }
+
+ /**
+ * @param \Vendidero\Germanized\Shipments\Shipment $shipment
+ */
+ public function get_available_label_products( $shipment ) {
+ return wc_gzd_dhl_get_products( $shipment->get_country() );
+ }
+
+ /**
+ * @param \Vendidero\Germanized\Shipments\Shipment $shipment
+ */
+ public function get_available_label_services( $shipment ) {
+ return wc_gzd_dhl_get_services();
+ }
+
+ protected function get_available_base_countries() {
+ return Package::get_available_countries();
+ }
+
+ protected function get_general_settings() {
+ $settings = array(
+ array( 'title' => '', 'type' => 'title', 'id' => 'dhl_general_options' ),
+
+ array(
+ 'title' => _x( 'Customer Number (EKP)', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'desc' => '',
+ 'id' => 'account_number',
+ 'value' => $this->get_setting( 'account_number', '' ),
+ 'placeholder' => '1234567890',
+ 'custom_attributes' => array( 'maxlength' => '10' )
+ ),
+
+ array( 'type' => 'sectionend', 'id' => 'dhl_general_options' ),
+
+ array( 'title' => _x( 'API', 'dhl', 'woocommerce-germanized' ), 'type' => 'title', 'id' => 'dhl_api_options' ),
+
+ array(
+ 'title' => _x( 'Enable Sandbox', 'dhl', 'woocommerce-germanized' ),
+ 'desc' => _x( 'Activate Sandbox mode for testing purposes.', 'dhl', 'woocommerce-germanized' ),
+ 'id' => 'sandbox_mode',
+ 'value' => wc_bool_to_string( $this->get_setting( 'sandbox_mode', 'no' ) ),
+ 'type' => 'gzd_toggle',
+ ),
+
+ array(
+ 'title' => _x( 'Live Username', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'desc' => '',
+ 'id' => 'api_username',
+ 'default' => '',
+ 'value' => $this->get_setting( 'api_username', '' ),
+ 'custom_attributes' => array( 'data-show_if_sandbox_mode' => 'no', 'autocomplete' => 'new-password' )
+ ),
+
+ array(
+ 'title' => _x( 'Live Password', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'password',
+ 'desc' => '' . sprintf( _x( 'Your password to the DHL business customer portal. Please note the new assignment of the password to 3 (Standard User) or 12 (System User) months and make sure to test your access data in advance %s.', 'dhl', 'woocommerce-germanized' ), '
' . _x( 'here', 'dhl', 'woocommerce-germanized' ) .' ' ) . '
',
+ 'id' => 'api_password',
+ 'value' => $this->get_setting( 'api_password', '' ),
+ 'custom_attributes' => array( 'data-show_if_sandbox_mode' => 'no', 'autocomplete' => 'new-password' )
+ ),
+
+ array(
+ 'title' => _x( 'Sandbox Username', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'desc' => '',
+ 'id' => 'api_sandbox_username',
+ 'value' => $this->get_setting( 'api_sandbox_username', '' ),
+ 'custom_attributes' => array( 'data-show_if_sandbox_mode' => '', 'autocomplete' => 'new-password' )
+ ),
+
+ array(
+ 'title' => _x( 'Sandbox Password', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'password',
+ 'desc' => '',
+ 'id' => 'api_sandbox_password',
+ 'value' => $this->get_setting( 'api_sandbox_password', '' ),
+ 'custom_attributes' => array( 'data-show_if_sandbox_mode' => '', 'autocomplete' => 'new-password' )
+ ),
+
+ array( 'type' => 'sectionend', 'id' => 'dhl_api_options' ),
+
+ array( 'title' => _x( 'Products and Participation Numbers', 'dhl', 'woocommerce-germanized' ), 'type' => 'title', 'id' => 'dhl_api_options' ),
+ );
+
+ $dhl_products = array();
+
+ foreach( ( wc_gzd_dhl_get_products_domestic() + wc_gzd_dhl_get_products_international() ) as $product => $title ) {
+ $dhl_products[] = array(
+ 'title' => $title,
+ 'type' => 'text',
+ 'id' => 'participation_' . $product,
+ 'default' => '',
+ 'value' => $this->get_setting( 'participation_' . $product, '' ),
+ 'custom_attributes' => array( 'maxlength' => '2' ),
+ );
+ }
+
+ $dhl_products[] = array(
+ 'title' => _x( 'Inlay Returns', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'default' => '',
+ 'value' => $this->get_setting( 'participation_return', '' ),
+ 'custom_attributes' => array( 'maxlength' => '2' ),
+ );
+
+ $settings = array_merge( $settings, $dhl_products );
+
+ $settings = array_merge( $settings, array(
+ array( 'type' => 'sectionend', 'id' => 'dhl_product_options' ),
+ array( 'title' => _x( 'Tracking', 'dhl', 'woocommerce-germanized' ), 'type' => 'title', 'id' => 'tracking_options' ),
+ ) );
+
+ $general_settings = parent::get_general_settings();
+
+ return array_merge( $settings, $general_settings );
+ }
+
+ protected function get_pickup_settings() {
+ $settings = array(
+ array( 'title' => '', 'type' => 'title', 'id' => 'dhl_pickup_options', 'allow_override' => true ),
+
+ array(
+ 'title' => _x( 'Packstation', 'dhl', 'woocommerce-germanized' ),
+ 'desc' => _x( 'Enable delivery to Packstation.', 'dhl', 'woocommerce-germanized' ),
+ 'desc_tip' => _x( 'Let customers choose a Packstation as delivery address.', 'dhl', 'woocommerce-germanized' ),
+ 'id' => 'parcel_pickup_packstation_enable',
+ 'value' => wc_bool_to_string( $this->get_setting( 'parcel_pickup_packstation_enable' ) ),
+ 'default' => 'yes',
+ 'type' => 'gzd_toggle',
+ ),
+
+ array(
+ 'title' => _x( 'Postoffice', 'dhl', 'woocommerce-germanized' ),
+ 'desc' => _x( 'Enable delivery to Post Offices.', 'dhl', 'woocommerce-germanized' ),
+ 'desc_tip' => _x( 'Let customers choose a Post Office as delivery address.', 'dhl', 'woocommerce-germanized' ),
+ 'id' => 'parcel_pickup_postoffice_enable',
+ 'value' => wc_bool_to_string( $this->get_setting( 'parcel_pickup_postoffice_enable' ) ),
+ 'default' => 'yes',
+ 'type' => 'gzd_toggle',
+ ),
+
+ array(
+ 'title' => _x( 'Parcel Shop', 'dhl', 'woocommerce-germanized' ),
+ 'desc' => _x( 'Enable delivery to Parcel Shops.', 'dhl', 'woocommerce-germanized' ),
+ 'desc_tip' => _x( 'Let customers choose a Parcel Shop as delivery address.', 'dhl', 'woocommerce-germanized' ),
+ 'id' => 'parcel_pickup_parcelshop_enable',
+ 'value' => wc_bool_to_string( $this->get_setting( 'parcel_pickup_parcelshop_enable' ) ),
+ 'default' => 'yes',
+ 'type' => 'gzd_toggle',
+ ),
+
+ array(
+ 'title' => _x( 'Map', 'dhl', 'woocommerce-germanized' ),
+ 'desc' => _x( 'Let customers find a DHL location on a map.', 'dhl', 'woocommerce-germanized' ) . '' . _x( 'Enable this option to let your customers choose a pickup option from a map within the checkout. If this option is disabled a link to the DHL website is placed instead.', 'dhl', 'woocommerce-germanized' ) . '
',
+ 'id' => 'parcel_pickup_map_enable',
+ 'value' => wc_bool_to_string( $this->get_setting( 'parcel_pickup_map_enable' ) ),
+ 'default' => 'no',
+ 'type' => 'gzd_toggle',
+ 'allow_override' => false,
+ ),
+
+ array(
+ 'title' => _x( 'Google Maps Key', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'password',
+ 'id' => 'parcel_pickup_map_api_password',
+ 'custom_attributes' => array( 'data-show_if_parcel_pickup_map_enable' => '' ),
+ 'value' => $this->get_setting( 'parcel_pickup_map_api_password' ),
+ 'desc' => '',
+ 'default' => '',
+ 'allow_override' => false,
+ ),
+
+ array(
+ 'title' => _x( 'Limit results', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'number',
+ 'id' => 'parcel_pickup_map_max_results',
+ 'custom_attributes' => array( 'data-show_if_parcel_pickup_map_enable' => '' ),
+ 'value' => $this->get_setting( 'parcel_pickup_map_max_results' ),
+ 'desc_tip' => _x( 'Limit the number of DHL locations shown on the map', 'dhl', 'woocommerce-germanized' ),
+ 'default' => 20,
+ 'css' => 'max-width: 60px;',
+ 'allow_override' => false,
+ ),
+
+ array( 'type' => 'sectionend', 'id' => 'dhl_pickup_options' ),
+ );
+
+ return $settings;
+ }
+
+ protected function get_preferred_settings() {
+ $wc_gateway_titles = array();
+
+ if ( function_exists( 'WC' ) && WC()->payment_gateways() ) {
+ $wc_payment_gateways = WC()->payment_gateways()->payment_gateways();
+ $wc_gateway_titles = wp_list_pluck( $wc_payment_gateways, 'method_title', 'id' );
+ }
+
+ $settings = array(
+ array( 'title' => '', 'type' => 'title', 'id' => 'preferred_options', 'allow_override' => true ),
+
+ array(
+ 'title' => _x( 'Preferred Day', 'dhl', 'woocommerce-germanized' ),
+ 'desc' => _x( 'Enable preferred day delivery.', 'dhl', 'woocommerce-germanized' ) . '' . _x( 'Enabling this option will display options for the user to select their preferred day of delivery during the checkout.', 'dhl', 'woocommerce-germanized' ) . '
',
+ 'id' => 'PreferredDay_enable',
+ 'value' => wc_bool_to_string( $this->get_setting( 'PreferredDay_enable' ) ),
+ 'default' => 'yes',
+ 'type' => 'gzd_toggle',
+ ),
+
+ array(
+ 'title' => _x( 'Fee', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'desc' => _x( 'Insert gross value as surcharge for preferred day delivery. Insert 0 to offer service for free.', 'dhl', 'woocommerce-germanized' ),
+ 'desc_tip' => true,
+ 'id' => 'PreferredDay_cost',
+ 'value' => $this->get_setting( 'PreferredDay_cost' ),
+ 'default' => '1.2',
+ 'css' => 'max-width: 60px;',
+ 'class' => 'wc_input_decimal',
+ 'custom_attributes' => array( 'data-show_if_woocommerce_gzd_dhl_PreferredDay_enable' => '' )
+ ),
+
+ array(
+ 'title' => _x( 'Preferred Location', 'dhl', 'woocommerce-germanized' ),
+ 'desc' => _x( 'Enable preferred location delivery.', 'dhl', 'woocommerce-germanized' ) . '' . _x( 'Enabling this option will display options for the user to select their preferred delivery location during the checkout.', 'dhl', 'woocommerce-germanized' ) . '
',
+ 'id' => 'PreferredLocation_enable',
+ 'value' => wc_bool_to_string( $this->get_setting( 'PreferredLocation_enable' ) ),
+ 'default' => 'yes',
+ 'type' => 'gzd_toggle',
+ ),
+
+ array(
+ 'title' => _x( 'Preferred Neighbor', 'dhl', 'woocommerce-germanized' ),
+ 'desc' => _x( 'Enable preferred neighbor delivery.', 'dhl', 'woocommerce-germanized' ) . '' . _x( 'Enabling this option will display options for the user to deliver to their preferred neighbor during the checkout.', 'dhl', 'woocommerce-germanized' ) . '
',
+ 'id' => 'PreferredNeighbour_enable',
+ 'value' => wc_bool_to_string( $this->get_setting( 'PreferredNeighbour_enable' ) ),
+ 'default' => 'yes',
+ 'type' => 'gzd_toggle',
+ ),
+
+ array(
+ 'title' => _x( 'Cut-off time', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'time',
+ 'id' => 'PreferredDay_cutoff_time',
+ 'allow_override' => false,
+ 'value' => $this->get_setting( 'PreferredDay_cutoff_time' ),
+ 'desc' => '' . _x( 'The cut-off time is the latest possible order time up to which the minimum preferred day (day of order + 2 working days) can be guaranteed. As soon as the time is exceeded, the earliest preferred day displayed in the frontend will be shifted to one day later (day of order + 3 working days).', 'dhl', 'woocommerce-germanized' ) . '
',
+ 'default' => '12:00',
+ 'custom_attributes' => array( 'data-show_if_woocommerce_gzd_dhl_PreferredDay_enable' => '' )
+ ),
+
+ array(
+ 'title' => _x( 'Preparation days', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'number',
+ 'id' => 'PreferredDay_preparation_days',
+ 'allow_override' => false,
+ 'value' => $this->get_setting( 'PreferredDay_preparation_days' ),
+ 'desc' => '' . _x( 'If you need more time to prepare your shipments you might want to add a static preparation time to the possible starting date for preferred day delivery.', 'dhl', 'woocommerce-germanized' ) . '
',
+ 'default' => '0',
+ 'css' => 'max-width: 60px',
+ 'custom_attributes' => array( 'data-show_if_woocommerce_gzd_dhl_PreferredDay_enable' => '', 'min' => 0, 'max' => 3 )
+ ),
+
+ array(
+ 'title' => _x( 'Exclude days of transfer', 'dhl', 'woocommerce-germanized' ),
+ 'desc' => _x( 'Monday', 'dhl', 'woocommerce-germanized' ),
+ 'desc_tip' => _x( 'Exclude days from transferring shipments to DHL.', 'dhl', 'woocommerce-germanized' ),
+ 'value' => wc_bool_to_string( $this->get_setting( 'PreferredDay_exclusion_mon' ) ),
+ 'id' => 'PreferredDay_exclusion_mon',
+ 'allow_override' => false,
+ 'type' => 'gzd_toggle',
+ 'default' => 'no',
+ 'checkboxgroup' => 'start',
+ 'custom_attributes' => array( 'data-show_if_woocommerce_gzd_dhl_PreferredDay_enable' => '' )
+ ),
+
+ array(
+ 'desc' => _x( 'Tuesday', 'dhl', 'woocommerce-germanized' ),
+ 'id' => 'PreferredDay_exclusion_tue',
+ 'value' => wc_bool_to_string( $this->get_setting( 'PreferredDay_exclusion_tue' ) ),
+ 'type' => 'gzd_toggle',
+ 'allow_override' => false,
+ 'default' => 'no',
+ 'checkboxgroup' => '',
+ 'custom_attributes' => array( 'data-show_if_woocommerce_gzd_dhl_PreferredDay_enable' => '' )
+ ),
+
+ array(
+ 'desc' => _x( 'Wednesday', 'dhl', 'woocommerce-germanized' ),
+ 'id' => 'PreferredDay_exclusion_wed',
+ 'value' => wc_bool_to_string( $this->get_setting( 'PreferredDay_exclusion_wed' ) ),
+ 'type' => 'gzd_toggle',
+ 'allow_override' => false,
+ 'default' => 'no',
+ 'checkboxgroup' => '',
+ 'custom_attributes' => array( 'data-show_if_woocommerce_gzd_dhl_PreferredDay_enable' => '' )
+ ),
+
+ array(
+ 'desc' => _x( 'Thursday', 'dhl', 'woocommerce-germanized' ),
+ 'id' => 'PreferredDay_exclusion_thu',
+ 'value' => wc_bool_to_string( $this->get_setting( 'PreferredDay_exclusion_thu' ) ),
+ 'type' => 'gzd_toggle',
+ 'allow_override' => false,
+ 'default' => 'no',
+ 'checkboxgroup' => '',
+ 'custom_attributes' => array( 'data-show_if_woocommerce_gzd_dhl_PreferredDay_enable' => '' )
+ ),
+
+ array(
+ 'desc' => _x( 'Friday', 'dhl', 'woocommerce-germanized' ),
+ 'id' => 'PreferredDay_exclusion_fri',
+ 'value' => wc_bool_to_string( $this->get_setting( 'PreferredDay_exclusion_fri' ) ),
+ 'type' => 'gzd_toggle',
+ 'allow_override' => false,
+ 'default' => 'no',
+ 'checkboxgroup' => '',
+ 'custom_attributes' => array( 'data-show_if_woocommerce_gzd_dhl_PreferredDay_enable' => '' )
+ ),
+
+ array(
+ 'desc' => _x( 'Saturday', 'dhl', 'woocommerce-germanized' ),
+ 'id' => 'PreferredDay_exclusion_sat',
+ 'value' => wc_bool_to_string( $this->get_setting( 'PreferredDay_exclusion_sat' ) ),
+ 'type' => 'gzd_toggle',
+ 'allow_override' => false,
+ 'default' => 'no',
+ 'checkboxgroup' => 'end',
+ 'custom_attributes' => array( 'data-show_if_woocommerce_gzd_dhl_PreferredDay_enable' => '' )
+ ),
+
+ array(
+ 'title' => _x( 'Exclude gateways', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'multiselect',
+ 'desc' => _x( 'Select payment gateways to be excluded from showing preferred services.', 'dhl', 'woocommerce-germanized' ),
+ 'desc_tip' => true,
+ 'allow_override' => false,
+ 'id' => 'preferred_payment_gateways_excluded',
+ 'value' => $this->get_setting( 'preferred_payment_gateways_excluded' ),
+ 'options' => $wc_gateway_titles,
+ 'class' => 'wc-enhanced-select',
+ ),
+
+ array( 'type' => 'sectionend', 'id' => 'preferred_options' ),
+ );
+
+ return $settings;
+ }
+
+ protected function get_label_settings() {
+ $select_dhl_product_dom = wc_gzd_dhl_get_products_domestic();
+ $select_dhl_product_int = wc_gzd_dhl_get_products_international();
+ $duties = wc_gzd_dhl_get_duties();
+ $ref_placeholders = wc_gzd_dhl_get_label_payment_ref_placeholder();
+ $ref_placeholders_str = implode( ', ', array_keys( $ref_placeholders ) );
+
+ $settings = array(
+ array( 'title' => '', 'title_method' => _x( 'Products', 'dhl', 'woocommerce-germanized' ), 'type' => 'title', 'id' => 'shipping_provider_dhl_label_options', 'allow_override' => true ),
+
+ array(
+ 'title' => _x( 'Domestic Default Service', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'select',
+ 'id' => 'label_default_product_dom',
+ 'default' => 'V01PAK',
+ 'value' => $this->get_setting( 'label_default_product_dom', 'V01PAK' ),
+ 'desc' => '' . _x( 'Please select your default DHL shipping service for domestic shipments that you want to offer to your customers (you can always change this within each individual shipment afterwards).', 'dhl', 'woocommerce-germanized' ) . '
',
+ 'options' => $select_dhl_product_dom,
+ 'class' => 'wc-enhanced-select',
+ ),
+
+ array(
+ 'title' => _x( 'Int. Default Service', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'select',
+ 'default' => 'V55PAK',
+ 'value' => $this->get_setting( 'label_default_product_int', 'V55PAK' ),
+ 'id' => 'label_default_product_int',
+ 'desc' => '' . _x( 'Please select your default DHL shipping service for cross-border shipments that you want to offer to your customers (you can always change this within each individual shipment afterwards).', 'dhl', 'woocommerce-germanized' ) . '
',
+ 'options' => $select_dhl_product_int,
+ 'class' => 'wc-enhanced-select',
+ ),
+
+ array(
+ 'title' => _x( 'Default Duty', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'select',
+ 'default' => 'DDP',
+ 'id' => 'label_default_duty',
+ 'value' => $this->get_setting( 'label_default_duty', 'DDP' ),
+ 'desc' => _x( 'Please select a default duty type.', 'dhl', 'woocommerce-germanized' ),
+ 'desc_tip' => true,
+ 'options' => $duties,
+ 'class' => 'wc-enhanced-select',
+ ),
+
+ array(
+ 'title' => _x( 'Codeable', 'dhl', 'woocommerce-germanized' ),
+ 'desc' => _x( 'Generate label only if address can be automatically retrieved DHL.', 'dhl', 'woocommerce-germanized' ),
+ 'id' => 'label_address_codeable_only',
+ 'value' => $this->get_setting( 'label_address_codeable_only', 'no' ),
+ 'default' => 'no',
+ 'type' => 'gzd_toggle',
+ 'allow_override' => false,
+ 'desc_tip' => _x( 'Choose this option if you want to make sure that by default labels are only generated for codeable addresses.', 'dhl', 'woocommerce-germanized' ),
+ ),
+
+ array(
+ 'title' => _x( 'Force email', 'dhl', 'woocommerce-germanized' ),
+ 'desc' => _x( 'Force transferring customer email to DHL.', 'dhl', 'woocommerce-germanized' ) . '' . _x( 'By default the customer email address is only transferred in case explicit consent has been given via a checkbox during checkout. You may force to transfer the customer email address during label creation to make sure your customers receive email notifications by DHL. Make sure to check your privacy policy and seek advice by a lawyer in case of doubt.', 'dhl', 'woocommerce-germanized' ) . '
',
+ 'id' => 'label_force_email_transfer',
+ 'value' => $this->get_setting( 'label_force_email_transfer', 'no' ),
+ 'default' => 'no',
+ 'allow_override' => false,
+ 'type' => 'gzd_toggle',
+ ),
+ array(
+ 'title' => _x( 'Inlay Returns', 'dhl', 'woocommerce-germanized' ),
+ 'desc' => _x( 'Additionally create inlay return labels for shipments that support returns.', 'dhl', 'woocommerce-germanized' ),
+ 'id' => 'label_auto_inlay_return_label',
+ 'value' => $this->get_setting( 'label_auto_inlay_return_label', 'no' ),
+ 'default' => 'no',
+ 'type' => 'gzd_toggle',
+ ),
+
+ array( 'type' => 'sectionend', 'id' => 'shipping_provider_dhl_label_options' ),
+ );
+
+ $settings = array_merge( $settings, parent::get_label_settings() );
+
+ $settings = array_merge( $settings, array(
+ array( 'title' => _x( 'Retoure', 'dhl', 'woocommerce-germanized' ), 'type' => 'title', 'id' => 'dhl_retoure_options', 'desc' => sprintf( _x( 'Adjust handling of return shipments through the DHL Retoure API. Make sure that your %s contains DHL Retoure Online.', 'dhl', 'woocommerce-germanized' ), '' . _x( 'contract', 'dhl', 'woocommerce-germanized' ) . ' ' ) ),
+
+ array(
+ 'title' => _x( 'Retoure', 'dhl', 'woocommerce-germanized' ),
+ 'desc' => _x( 'Enable creating labels for return shipments.', 'dhl', 'woocommerce-germanized' ) . '' . _x( 'By enabling this option you might generate retoure labels for return shipments and send them to your customer via email.', 'dhl', 'woocommerce-germanized' ) . '
',
+ 'id' => 'label_retoure_enable',
+ 'value' => wc_bool_to_string( $this->enable_retoure() ),
+ 'default' => 'yes',
+ 'type' => 'gzd_toggle',
+ ),
+
+ array(
+ 'type' => 'dhl_receiver_ids',
+ 'value' => $this->get_setting( 'retoure_receiver_ids', array() ),
+ 'id' => 'retoure_receiver_ids',
+ 'default' => array(),
+ ),
+
+ array( 'type' => 'sectionend', 'id' => 'dhl_retoure_options' ),
+
+ array( 'title' => _x( 'Default Services', 'dhl', 'woocommerce-germanized' ), 'allow_override' => true, 'type' => 'title', 'id' => 'dhl_label_default_services_options', 'desc' => sprintf( _x( 'Adjust services to be added to your labels by default. Find out more about these services .', 'dhl', 'woocommerce-germanized' ), 'https://www.dhl.de/de/geschaeftskunden/paket/leistungen-und-services/services/service-loesungen.html' ) ),
+ array(
+ 'title' => _x( 'GoGreen', 'dhl', 'woocommerce-germanized' ),
+ 'desc' => _x( 'Enable the GoGreen Service by default.', 'dhl', 'woocommerce-germanized' ),
+ 'id' => 'label_service_GoGreen',
+ 'value' => wc_bool_to_string( $this->get_setting( 'label_service_GoGreen', 'no' ) ),
+ 'default' => 'no',
+ 'type' => 'gzd_toggle',
+ ),
+ array(
+ 'title' => _x( 'Additional Insurance', 'dhl', 'woocommerce-germanized' ),
+ 'desc' => _x( 'Add an additional insurance to labels.', 'dhl', 'woocommerce-germanized' ),
+ 'id' => 'label_service_AdditionalInsurance',
+ 'value' => wc_bool_to_string( $this->get_setting( 'label_service_AdditionalInsurance', 'no' ) ),
+ 'default' => 'no',
+ 'type' => 'gzd_toggle',
+ ),
+ array(
+ 'title' => _x( 'Retail Outlet Routing', 'dhl', 'woocommerce-germanized' ),
+ 'desc' => _x( 'Send undeliverable items to nearest retail outlet instead of immediate return.', 'dhl', 'woocommerce-germanized' ),
+ 'id' => 'label_service_ParcelOutletRouting',
+ 'value' => wc_bool_to_string( $this->get_setting( 'label_service_ParcelOutletRouting', 'no' ) ),
+ 'default' => 'no',
+ 'type' => 'gzd_toggle',
+ ),
+ array(
+ 'title' => _x( 'No Neighbor', 'dhl', 'woocommerce-germanized' ),
+ 'desc' => _x( 'Do not deliver to neighbors.', 'dhl', 'woocommerce-germanized' ),
+ 'id' => 'label_service_NoNeighbourDelivery',
+ 'value' => wc_bool_to_string( $this->get_setting( 'label_service_NoNeighbourDelivery', 'no' ) ),
+ 'default' => 'no',
+ 'type' => 'gzd_toggle',
+ ),
+ array(
+ 'title' => _x( 'Named person only', 'dhl', 'woocommerce-germanized' ),
+ 'desc' => _x( 'Do only delivery to named person.', 'dhl', 'woocommerce-germanized' ),
+ 'id' => 'label_service_NamedPersonOnly',
+ 'value' => wc_bool_to_string( $this->get_setting( 'label_service_NamedPersonOnly', 'no' ) ),
+ 'default' => 'no',
+ 'type' => 'gzd_toggle',
+ ),
+ array(
+ 'title' => _x( 'Bulky Goods', 'dhl', 'woocommerce-germanized' ),
+ 'desc' => _x( 'Deliver as bulky goods.', 'dhl', 'woocommerce-germanized' ),
+ 'id' => 'label_service_BulkyGoods',
+ 'value' => wc_bool_to_string( $this->get_setting( 'label_service_BulkyGoods', 'no' ) ),
+ 'default' => 'no',
+ 'type' => 'gzd_toggle',
+ ),
+ array(
+ 'title' => _x( 'Minimum age (Visual check)', 'dhl', 'woocommerce-germanized' ),
+ 'id' => 'label_visual_min_age',
+ 'type' => 'select',
+ 'default' => '0',
+ 'value' => $this->get_setting( 'label_visual_min_age', '0' ),
+ 'options' => wc_gzd_dhl_get_visual_min_ages(),
+ 'desc_tip' => _x( 'Choose this option if you want to let DHL check your customer\'s age.', 'dhl', 'woocommerce-germanized' ),
+ ),
+ array(
+ 'title' => _x( 'Sync (Visual Check)', 'dhl', 'woocommerce-germanized' ),
+ 'desc' => _x( 'Visually verify age if shipment contains applicable items.', 'dhl', 'woocommerce-germanized' ) . '',
+ 'id' => 'label_auto_age_check_sync',
+ 'value' => wc_bool_to_string( $this->get_setting( 'label_auto_age_check_sync', 'yes' ) ),
+ 'default' => 'yes',
+ 'type' => 'gzd_toggle',
+ ),
+ array(
+ 'title' => _x( 'Minimum age (Ident check)', 'dhl', 'woocommerce-germanized' ),
+ 'id' => 'label_ident_min_age',
+ 'type' => 'select',
+ 'default' => '0',
+ 'value' => $this->get_setting( 'label_ident_min_age', '0' ),
+ 'options' => wc_gzd_dhl_get_ident_min_ages(),
+ 'desc_tip' => _x( 'Choose this option if you want to let DHL check your customer\'s identity and age.', 'dhl', 'woocommerce-germanized' ),
+ ),
+ array(
+ 'title' => _x( 'Sync (Ident Check)', 'dhl', 'woocommerce-germanized' ),
+ 'desc' => _x( 'Verify identity and age if shipment contains applicable items.', 'dhl', 'woocommerce-germanized' ) . '',
+ 'id' => 'label_auto_age_check_ident_sync',
+ 'value' => wc_bool_to_string( $this->get_setting( 'label_auto_age_check_ident_sync', 'no' ) ),
+ 'default' => 'no',
+ 'type' => 'gzd_toggle',
+ ),
+ array(
+ 'title' => _x( 'Premium', 'dhl', 'woocommerce-germanized' ),
+ 'desc' => _x( 'Premium delivery for international shipments.', 'dhl', 'woocommerce-germanized' ),
+ 'id' => 'label_service_Premium',
+ 'value' => wc_bool_to_string( $this->get_setting( 'label_service_Premium', 'no' ) ),
+ 'default' => 'no',
+ 'type' => 'gzd_toggle',
+ ),
+ array( 'type' => 'sectionend', 'id' => 'dhl_label_default_services_options' ),
+
+ array( 'title' => _x( 'Bank Account', 'dhl', 'woocommerce-germanized' ), 'type' => 'title', 'id' => 'dhl_bank_account_options', 'desc' => _x( 'Enter your bank details needed for services that use COD.', 'dhl', 'woocommerce-germanized' ) ),
+
+ array(
+ 'title' => _x( 'Holder', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'id' => 'bank_holder',
+ 'value' => $this->get_setting( 'bank_holder' ),
+ 'default' => Package::get_default_bank_account_data( 'name' ),
+ ),
+
+ array(
+ 'title' => _x( 'Bank Name', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'id' => 'bank_name',
+ 'value' => $this->get_setting( 'bank_name' ),
+ 'default' => Package::get_default_bank_account_data( 'bank_name' ),
+ ),
+
+ array(
+ 'title' => _x( 'IBAN', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'id' => 'bank_iban',
+ 'value' => $this->get_setting( 'bank_iban' ),
+ 'default' => Package::get_default_bank_account_data( 'iban' ),
+ ),
+
+ array(
+ 'title' => _x( 'BIC', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'id' => 'bank_bic',
+ 'value' => $this->get_setting( 'bank_bic' ),
+ 'default' => Package::get_default_bank_account_data( 'bic' ),
+ ),
+
+ array(
+ 'title' => _x( 'Payment Reference', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'id' => 'bank_ref',
+ 'custom_attributes' => array( 'maxlength' => '35' ),
+ 'value' => $this->get_setting( 'bank_ref' ),
+ 'desc' => '' . sprintf( _x( 'Use these placeholders to add info to the payment reference: %s. This text is limited to 35 characters.', 'dhl', 'woocommerce-germanized' ), '' . esc_html( $ref_placeholders_str ) . '
' ) . '
',
+ 'default' => '{shipment_id}'
+ ),
+
+ array(
+ 'title' => _x( 'Payment Reference 2', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'id' => 'bank_ref_2',
+ 'custom_attributes' => array( 'maxlength' => '35' ),
+ 'value' => $this->get_setting( 'bank_ref_2' ),
+ 'desc' => '' . sprintf( _x( 'Use these placeholders to add info to the payment reference: %s. This text is limited to 35 characters.', 'dhl', 'woocommerce-germanized' ), '' . esc_html( $ref_placeholders_str ) . '
' ) . '
',
+ 'default' => '{email}'
+ ),
+
+ array( 'type' => 'sectionend', 'id' => 'dhl_bank_account_options' ),
+ ) );
+
+ return $settings;
+ }
+
+ public function get_help_link() {
+ return 'https://vendidero.de/dokumentation/woocommerce-germanized/post-dhl';
+ }
+
+ public function get_signup_link() {
+ return 'https://www.dhl.de/de/geschaeftskunden/paket/plugin-kunde-werden/angebot-dhl-geschaeftskunden-online.html?source=woocommercegermanized';
+ }
+
+ public function get_settings_help_pointers( $section = '' ) {
+ $pointers = array();
+
+ if ( '' === $section ) {
+ $pointers = array(
+ 'pointers' => array(
+ 'account' => array(
+ 'target' => '#account_number',
+ 'next' => 'api',
+ 'next_url' => '',
+ 'next_trigger' => array(),
+ 'options' => array(
+ 'content' => '' . esc_html_x( 'Customer Number', 'dhl', 'woocommerce-germanized' ) . ' ' .
+ '' . esc_html_x( 'Insert your DHL business customer number (EKP) here. If you are not yet a business customer you might want to create a new account first.', 'dhl', 'woocommerce-germanized' ) . '
',
+ 'position' => array(
+ 'edge' => 'left',
+ 'align' => 'left',
+ ),
+ ),
+ ),
+ 'api' => array(
+ 'target' => Package::is_debug_mode() ? '#api_sandbox_username' : '#api_username',
+ 'next' => '',
+ 'next_url' => add_query_arg( array( 'tutorial' => 'yes' ), $this->get_edit_link( 'label' ) ),
+ 'next_trigger' => array(),
+ 'options' => array(
+ 'content' => '' . esc_html_x( 'API Access', 'dhl', 'woocommerce-germanized' ) . ' ' .
+ '' . esc_html_x( 'To create labels and embed DHL services, our software needs access to the API. You will need to fill out the username and password fields accordingly.', 'dhl', 'woocommerce-germanized' ) . '
',
+ 'position' => array(
+ 'edge' => 'left',
+ 'align' => 'left',
+ ),
+ ),
+ ),
+ ),
+ );
+ } elseif( 'label' === $section ) {
+ $pointers = array(
+ 'pointers' => array(
+ 'inlay' => array(
+ 'target' => '#label_auto_inlay_return_label-toggle',
+ 'next' => 'retoure',
+ 'next_url' => '',
+ 'next_trigger' => array(),
+ 'options' => array(
+ 'content' => '' . esc_html_x( 'Inlay Returns', 'dhl', 'woocommerce-germanized' ) . ' ' .
+ '' . esc_html_x( 'If you want to provide your customers with inlay return labels for your shipments you might enable this feature by default here.', 'dhl', 'woocommerce-germanized' ) . '
',
+ 'position' => array(
+ 'edge' => 'left',
+ 'align' => 'left',
+ ),
+ ),
+ ),
+ 'retoure' => array(
+ 'target' => '#label_retoure_enable-toggle',
+ 'next' => 'age_check',
+ 'next_url' => '',
+ 'next_trigger' => array(),
+ 'options' => array(
+ 'content' => '' . esc_html_x( 'Retoure', 'dhl', 'woocommerce-germanized' ) . ' ' .
+ '' . esc_html_x( 'If you want to create DHL labels to returns you should activate this feature. Make sure that you have DHL Online Retoure activated in your contract.', 'dhl', 'woocommerce-germanized' ) . '
',
+ 'position' => array(
+ 'edge' => 'left',
+ 'align' => 'left',
+ ),
+ ),
+ ),
+ 'age_check' => array(
+ 'target' => '#label_auto_age_check_sync-toggle',
+ 'next' => '',
+ 'next_url' => add_query_arg( array( 'tutorial' => 'yes' ), $this->get_edit_link( 'automation' ) ),
+ 'next_trigger' => array(),
+ 'options' => array(
+ 'content' => '' . esc_html_x( 'Age verification', 'dhl', 'woocommerce-germanized' ) . ' ' .
+ '' . esc_html_x( 'Use this feature to sync the Germanized age verification checkbox with the DHL visual minimum age verification service. As soon as applicable products are contained within the shipment, the service will be booked by default.', 'dhl', 'woocommerce-germanized' ) . '
',
+ 'position' => array(
+ 'edge' => 'left',
+ 'align' => 'left',
+ ),
+ ),
+ ),
+ )
+ );
+ } elseif( 'automation' === $section ) {
+ $pointers = array(
+ 'pointers' => array(
+ 'auto' => array(
+ 'target' => '#label_auto_enable-toggle',
+ 'next' => '',
+ 'next_url' => add_query_arg( array( 'tutorial' => 'yes' ), $this->get_edit_link( 'preferred' ) ),
+ 'next_trigger' => array(),
+ 'options' => array(
+ 'content' => '' . esc_html_x( 'Automation', 'dhl', 'woocommerce-germanized' ) . ' ' .
+ '' . esc_html_x( 'You might want to save some time and let Germanized generate labels automatically as soon as a shipment switches to a certain status.', 'dhl', 'woocommerce-germanized' ) . '
',
+ 'position' => array(
+ 'edge' => 'left',
+ 'align' => 'left',
+ ),
+ ),
+ )
+ )
+ );
+ } elseif( 'preferred' === $section ) {
+ $pointers = array(
+ 'pointers' => array(
+ 'day' => array(
+ 'target' => '#PreferredDay_enable-toggle',
+ 'next' => 'fee',
+ 'next_url' => '',
+ 'next_trigger' => array(),
+ 'options' => array(
+ 'content' => '' . esc_html_x( 'Preferred Day', 'dhl', 'woocommerce-germanized' ) . ' ' .
+ '' . esc_html_x( 'Let your customers choose a preferred day (if the service is available at the customer\'s location) of delivery within your checkout.', 'dhl', 'woocommerce-germanized' ) . '
',
+ 'position' => array(
+ 'edge' => 'left',
+ 'align' => 'left',
+ ),
+ ),
+ ),
+ 'fee' => array(
+ 'target' => '#PreferredDay_cost',
+ 'next' => 'location',
+ 'next_url' => '',
+ 'next_trigger' => array(),
+ 'options' => array(
+ 'content' => '' . esc_html_x( 'Fee', 'dhl', 'woocommerce-germanized' ) . ' ' .
+ '' . esc_html_x( 'Optionally charge your customers an additional fee for preferred services like preferred day.', 'dhl', 'woocommerce-germanized' ) . '
',
+ 'position' => array(
+ 'edge' => 'left',
+ 'align' => 'left',
+ ),
+ ),
+ ),
+ 'location' => array(
+ 'target' => '#PreferredLocation_enable-toggle',
+ 'next' => '',
+ 'next_url' => add_query_arg( array( 'tutorial' => 'yes' ), $this->get_edit_link( 'pickup' ) ),
+ 'next_trigger' => array(),
+ 'options' => array(
+ 'content' => '' . esc_html_x( 'Preferred Location', 'dhl', 'woocommerce-germanized' ) . ' ' .
+ '' . esc_html_x( 'Allow your customers to send their parcels to a preferred location e.g. a neighbor. This service is free of charge for DHL shipments.', 'dhl', 'woocommerce-germanized' ) . '
',
+ 'position' => array(
+ 'edge' => 'left',
+ 'align' => 'left',
+ ),
+ ),
+ ),
+ )
+ );
+ } elseif( 'pickup' === $section ) {
+ $pointers = array(
+ 'pointers' => array(
+ 'day' => array(
+ 'target' => '#parcel_pickup_packstation_enable-toggle',
+ 'next' => 'map',
+ 'next_url' => '',
+ 'next_trigger' => array(),
+ 'options' => array(
+ 'content' => '' . esc_html_x( 'Packstation', 'dhl', 'woocommerce-germanized' ) . ' ' .
+ '' . esc_html_x( 'Allow your customers to choose packstation (and/or other DHL location types as configured below) as shipping address.', 'dhl', 'woocommerce-germanized' ) . '
',
+ 'position' => array(
+ 'edge' => 'left',
+ 'align' => 'left',
+ ),
+ ),
+ ),
+ 'map' => array(
+ 'target' => '#parcel_pickup_map_enable-toggle',
+ 'next' => '',
+ 'next_url' => ProviderSettings::get_next_pointers_link( $this->get_name() ),
+ 'next_trigger' => array(),
+ 'options' => array(
+ 'content' => '' . esc_html_x( 'Map', 'dhl', 'woocommerce-germanized' ) . ' ' .
+ '' . esc_html_x( 'This option adds a map overlay view to let your customers choose a DHL location from a map nearby. You\'ll need a valid Google Maps API key to enable the map view.', 'dhl', 'woocommerce-germanized' ) . '
',
+ 'position' => array(
+ 'edge' => 'left',
+ 'align' => 'left',
+ ),
+ ),
+ ),
+ )
+ );
+ }
+
+ return $pointers;
+ }
+}
diff --git a/packages/woocommerce-germanized-dhl/src/ShippingProvider/DeutschePost.php b/packages/woocommerce-germanized-dhl/src/ShippingProvider/DeutschePost.php
new file mode 100644
index 000000000..4267ecc64
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/ShippingProvider/DeutschePost.php
@@ -0,0 +1,583 @@
+get_shipping_country() ) {
+ return false;
+ }
+
+ return parent::supports_customer_returns( $order );
+ }
+
+ public function supports_labels( $label_type, $shipment = false ) {
+ $label_types = array( 'simple', 'return' );
+
+ /**
+ * Return labels are only supported for DE
+ */
+ if ( 'return' === $label_type && $shipment && 'return' === $shipment->get_type() && 'DE' !== $shipment->get_sender_country() ) {
+ return false;
+ }
+
+ return in_array( $label_type, $label_types );
+ }
+
+ public function get_title( $context = 'view' ) {
+ return _x( 'Deutsche Post', 'dhl', 'woocommerce-germanized' );
+ }
+
+ public function get_name( $context = 'view' ) {
+ return 'deutsche_post';
+ }
+
+ public function get_description( $context = 'view' ) {
+ return _x( 'Integration for products of the Deutsche Post through Internetmarke.', 'dhl', 'woocommerce-germanized' );
+ }
+
+ public function get_default_tracking_url_placeholder() {
+ return 'https://www.deutschepost.de/sendung/simpleQueryResult.html?form.sendungsnummer={tracking_id}&form.einlieferungsdatum_tag={label_date_day}&form.einlieferungsdatum_monat={label_date_month}&form.einlieferungsdatum_jahr={label_date_year}';
+ }
+
+ public function get_api_username( $context = 'view' ) {
+ return $this->get_meta( 'api_username', true, $context );
+ }
+
+ public function set_api_username( $username ) {
+ $this->update_meta_data( 'api_username', strtolower( $username ) );
+ }
+
+ /**
+ * @param \Vendidero\Germanized\Shipments\Shipment $shipment
+ */
+ public function get_available_label_products( $shipment ) {
+ return wc_gzd_dhl_get_deutsche_post_products( $shipment );
+ }
+
+ protected function get_available_base_countries() {
+ return Package::get_available_countries();
+ }
+
+ protected function get_general_settings() {
+ $settings = array(
+ array( 'title' => '', 'type' => 'title', 'id' => 'deutsche_post_general_options' ),
+
+ array(
+ 'title' => _x( 'Username', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'desc' => '' . sprintf( _x( 'Your credentials to the
Portokasse . Please test your credentials before connecting.', 'dhl', 'woocommerce-germanized' ), 'https://portokasse.deutschepost.de/portokasse/#!/' ) . '
',
+ 'id' => 'api_username',
+ 'default' => '',
+ 'value' => $this->get_setting( 'api_username', '' ),
+ 'custom_attributes' => array( 'autocomplete' => 'new-password' )
+ ),
+
+ array(
+ 'title' => _x( 'Password', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'password',
+ 'id' => 'api_password',
+ 'default' => '',
+ 'value' => $this->get_setting( 'api_password', '' ),
+ 'custom_attributes' => array( 'autocomplete' => 'new-password' )
+ ),
+
+ array( 'type' => 'sectionend', 'id' => 'deutsche_post_general_options' ),
+ );
+
+ $settings = array_merge( $settings, array(
+ array( 'type' => 'sectionend', 'id' => 'dhl_product_options' ),
+
+ array( 'title' => _x( 'Tracking', 'dhl', 'woocommerce-germanized' ), 'type' => 'title', 'id' => 'tracking_options' ),
+ ) );
+
+ $general_settings = parent::get_general_settings();
+
+ return array_merge( $settings, $general_settings );
+ }
+
+ protected function get_label_settings() {
+ $api = Package::get_internetmarke_api();
+ $settings = parent::get_label_settings();
+
+ if ( $api && $api->is_configured() && $api->auth() && $api->is_available() ) {
+ $api->reload_products();
+
+ $balance = $api->get_balance( true );
+ $settings_url = $this->get_edit_link( 'label' );
+ $default_available_products = $api->get_default_available_products();
+
+ $settings = array_merge( $settings, array(
+ array( 'title' => _x( 'Portokasse', 'dhl', 'woocommerce-germanized' ), 'type' => 'title', 'id' => 'deutsche_post_portokasse_options' ),
+
+ array(
+ 'title' => _x( 'Balance', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'html',
+ 'html' => wc_price( Package::cents_to_eur( $balance ), array( 'currency' => 'EUR' ) ),
+ ),
+
+ array(
+ 'title' => _x( 'Charge (€)', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'html',
+ 'html' => $this->get_portokasse_charge_button(),
+ ),
+
+ array( 'type' => 'sectionend', 'id' => 'deutsche_post_portokasse_options' ),
+
+ array( 'title' => _x( 'Products', 'dhl', 'woocommerce-germanized' ), 'type' => 'title', 'id' => 'deutsche_post_product_options' ),
+
+ array(
+ 'title' => _x( 'Available Products', 'dhl', 'woocommerce-germanized' ),
+ 'id' => 'available_products',
+ 'class' => 'wc-enhanced-select',
+ 'desc' => '' . sprintf( _x( 'Choose the products you want to be available for your shipments from the list above. Manually
refresh the product list to make sure it is up-to-date.', 'dhl', 'woocommerce-germanized' ), wp_nonce_url( add_query_arg( array( 'action' => 'wc-gzd-dhl-im-product-refresh' ), $settings_url ), 'wc-gzd-dhl-refresh-im-products' ) ) . '
',
+ 'type' => 'multiselect',
+ 'value' => $this->get_setting( 'available_products', $default_available_products ),
+ 'options' => $this->get_product_select_options(),
+ 'default' => $default_available_products,
+ ),
+ ) );
+
+ $products = wc_gzd_dhl_get_deutsche_post_products_domestic( false, false );
+
+ if ( ! empty( $products ) ) {
+ $settings = array_merge( $settings, array(
+ array(
+ 'title' => _x( 'Domestic Default Service', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'select',
+ 'default' => '',
+ 'value' => $this->get_setting( 'label_default_product_dom', '' ),
+ 'id' => 'label_default_product_dom',
+ 'desc' => '' . _x( 'Please select your default shipping service for domestic shipments that you want to offer to your customers (you can always change this within each individual shipment afterwards).', 'dhl', 'woocommerce-germanized' ) . '
',
+ 'options' => wc_gzd_dhl_get_deutsche_post_products_domestic( false, false ),
+ 'class' => 'wc-enhanced-select',
+ ),
+
+ array(
+ 'title' => _x( 'EU Default Service', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'select',
+ 'default' => '',
+ 'value' => $this->get_setting( 'label_default_product_eu', '' ),
+ 'id' => 'label_default_product_eu',
+ 'desc' => '' . _x( 'Please select your default shipping service for EU shipments that you want to offer to your customers.', 'dhl', 'woocommerce-germanized' ) . '
',
+ 'options' => wc_gzd_dhl_get_deutsche_post_products_eu( false, false ),
+ 'class' => 'wc-enhanced-select',
+ ),
+
+ array(
+ 'title' => _x( 'Int. Default Service', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'select',
+ 'default' => '',
+ 'value' => $this->get_setting( 'label_default_product_int', '' ),
+ 'id' => 'label_default_product_int',
+ 'desc' => '' . _x( 'Please select your default shipping service for cross-border shipments that you want to offer to your customers.', 'dhl', 'woocommerce-germanized' ) . '
',
+ 'options' => wc_gzd_dhl_get_deutsche_post_products_international( false, false ),
+ 'class' => 'wc-enhanced-select',
+ ),
+ ) );
+ }
+
+ $settings = array_merge( $settings, array(
+ array( 'type' => 'sectionend', 'id' => 'deutsche_post_product_options' ),
+
+ array( 'title' => _x( 'Printing', 'dhl', 'woocommerce-germanized' ), 'type' => 'title', 'id' => 'deutsche_post_print_options' ),
+
+ array(
+ 'title' => _x( 'Default Format', 'dhl', 'woocommerce-germanized' ),
+ 'id' => 'label_default_page_format',
+ 'class' => 'wc-enhanced-select',
+ 'desc' => '' . sprintf( _x( 'Choose a print format which will be selected by default when creating labels. Manually
refresh available print formats to make sure the list is up-to-date.', 'dhl', 'woocommerce-germanized' ), wp_nonce_url( add_query_arg( array( 'action' => 'wc-gzd-dhl-im-page-formats-refresh' ), $settings_url ), 'wc-gzd-dhl-refresh-im-page-formats' ) ) . '
',
+ 'type' => 'select',
+ 'value' => $this->get_setting( 'label_default_page_format', 1 ),
+ 'options' => Package::get_internetmarke_api()->get_page_format_list(),
+ 'default' => 1,
+ ),
+ array(
+ 'title' => _x( 'Print X-axis column', 'dhl', 'woocommerce-germanized' ),
+ 'id' => 'label_position_x',
+ 'desc_tip' => _x( 'Adjust the print X-axis start column for the label.', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'number',
+ 'value' => $this->get_setting( 'label_position_x', 1 ),
+ 'custom_attributes' => array( 'min' => 0, 'step' => 1 ),
+ 'css' => 'max-width: 100px;',
+ 'default' => 1,
+ ),
+ array(
+ 'title' => _x( 'Print Y-axis column', 'dhl', 'woocommerce-germanized' ),
+ 'id' => 'label_position_y',
+ 'desc_tip' => _x( 'Adjust the print Y-axis start column for the label.', 'dhl', 'woocommerce-germanized' ),
+ 'type' => 'number',
+ 'value' => $this->get_setting( 'label_position_y', 1 ),
+ 'custom_attributes' => array( 'min' => 0, 'step' => 1 ),
+ 'css' => 'max-width: 100px;',
+ 'default' => 1,
+ ),
+
+ array( 'type' => 'sectionend', 'id' => 'deutsche_post_print_options' )
+ ) );
+ } elseif ( $api && $api->has_errors() ) {
+ $settings = array_merge( $settings, array(
+ array( 'title' => _x( 'API Error', 'dhl', 'woocommerce-germanized' ), 'type' => 'title', 'id' => 'deutsche_post_api_error', 'desc' => '' . implode( ", ", $api->get_errors()->get_error_messages() ) . '
' ),
+ array( 'type' => 'sectionend', 'id' => 'deutsche_post_api_error' )
+ ) );
+ }
+
+ return $settings;
+ }
+
+ protected function get_product_select_options() {
+ $products = Package::get_internetmarke_api()->get_products();
+ $options = wc_gzd_dhl_im_get_product_list( $products, false );
+
+ return $options;
+ }
+
+ /**
+ * @param \Vendidero\Germanized\Shipments\Shipment $shipment
+ */
+ public function get_label_fields( $shipment ) {
+ if ( ! Package::get_internetmarke_api()->is_available() ) {
+ return Package::get_internetmarke_api()->get_errors();
+ }
+
+ return parent::get_label_fields( $shipment );
+ }
+
+ protected function get_portokasse_charge_button() {
+ if ( ! Package::get_internetmarke_api()->get_user() ) {
+ return '';
+ }
+
+ $balance = Package::get_internetmarke_api()->get_balance();
+ $user_token = Package::get_internetmarke_api()->get_user()->getUserToken();
+ $settings_url = $this->get_edit_link();
+
+ $html = '
+
+ ' . _x( 'Charge Portokasse', 'dhl', 'woocommerce-germanized' ) . '
+ ' . sprintf( _x( 'The minimum amount is %s', 'dhl', 'woocommerce-germanized' ), wc_price( 10, array( 'currency' => 'EUR' ) ) ) . '
+ ';
+
+ return $html;
+ }
+
+ public function get_label_fields_html( $shipment ) {
+ $html = parent::get_label_fields_html( $shipment );
+ $html .= '
+
+ ';
+
+ return $html;
+ }
+
+ /**
+ * @param \Vendidero\Germanized\Shipments\Shipment $shipment
+ *
+ * @return array
+ */
+ protected function get_return_label_fields( $shipment ) {
+ return $this->get_simple_label_fields( $shipment );
+ }
+
+ /**
+ * @param \Vendidero\Germanized\Shipments\Shipment $shipment
+ *
+ * @return array|\WP_Error
+ */
+ protected function get_simple_label_fields( $shipment ) {
+ $settings = parent::get_simple_label_fields( $shipment );
+ $default_args = $this->get_default_available_label_args( $shipment );
+ $products = $this->get_available_label_products( $shipment );
+ $is_wp_int = false;
+
+ /**
+ * Replace the product id (which might contain services) with the default parent id.
+ * Otherwise the correct (parent only) product would not be selected from the available products lists.
+ */
+ if ( ! empty( $default_args['product_id'] ) ) {
+ foreach( $settings as $key => $setting ) {
+ if ( 'product_id' === $setting['id'] ) {
+ $settings[ $key ]['value'] = $default_args['product_id'];
+ }
+ }
+
+ $is_wp_int = Package::get_internetmarke_api()->is_warenpost_international( $default_args['product_id'] );
+ }
+
+ if ( empty( $products ) ) {
+ return new \WP_Error( 'dp-label-missing-products', sprintf( _x( 'Sorry but none of your selected Deutsche Post Products is available for this shipment. Please verify your shipment data (e.g. weight) and try again.', 'dhl', 'woocommerce-germanized' ), $this->get_edit_link( 'label' ) ) );
+ }
+
+ $settings = array_merge( $settings, $this->get_available_additional_services( $default_args['product_id'], $default_args['services'] ) );
+
+ if ( ! $is_wp_int ) {
+ $settings = array_merge( $settings, array(
+ array(
+ 'id' => 'page_format',
+ 'label' => _x( 'Page Format', 'dhl', 'woocommerce-germanized' ),
+ 'description' => '',
+ 'type' => 'select',
+ 'options' => Package::get_internetmarke_api()->get_page_format_list(),
+ 'value' => isset( $default_args['page_format'] ) ? $default_args['page_format'] : '',
+ )
+ ) );
+ }
+
+ return $settings;
+ }
+
+ public function get_available_additional_services( $product_id, $selected_services = array() ) {
+ $im_product_id = Package::get_internetmarke_api()->get_product_id( $product_id );
+ $services = \Vendidero\Germanized\DHL\Package::get_internetmarke_api()->get_product_list()->get_services_for_product( $im_product_id, $selected_services );
+ $settings = array(
+ array(
+ 'id' => 'additional-services',
+ 'type' => 'wrapper',
+ )
+ );
+
+ foreach( $services as $service ) {
+ $settings[] = array(
+ 'id' => 'service_' . $service,
+ 'name' => 'services[]',
+ 'wrapper_class' => 'form-field-checkbox',
+ 'type' => 'checkbox',
+ 'label' => \Vendidero\Germanized\DHL\Package::get_internetmarke_api()->get_product_list()->get_additional_service_title( $service ),
+ 'cbvalue' => $service,
+ 'value' => in_array( $service, $selected_services ) ? $service : '',
+ );
+ }
+
+ $settings[] = array(
+ 'type' => 'wrapper_end',
+ );
+
+ return $settings;
+ }
+
+ protected function get_default_available_label_args( $shipment, $default_args = array() ) {
+ if ( empty( $default_args ) ) {
+ $default_args = $this->get_default_label_props( $shipment );
+ }
+
+ $im_all_products = wc_gzd_dhl_get_deutsche_post_products( $shipment, false );
+ $default_product = isset( $default_args['product_id'] ) ? $default_args['product_id'] : array_keys( $im_all_products )[0];
+ $selected_product = isset( $im_all_products[ $default_product ] ) ? $default_product : array_keys( $im_all_products )[0];
+ $selected_services = isset( $default_args['services'] ) ? $default_args['services'] : array();
+
+ if ( ! empty( $selected_product ) ) {
+ /**
+ * Do only override services in case the product is a child product and force parent code.
+ */
+ if ( ! Package::get_internetmarke_api()->product_code_is_parent( $selected_product ) ) {
+ $selected_services = Package::get_internetmarke_api()->get_product_services( $selected_product );
+ $selected_product = Package::get_internetmarke_api()->get_product_parent_code( $selected_product );
+ }
+ }
+
+ return array_replace_recursive( $default_args, array(
+ 'services' => $selected_services,
+ 'product_id' => $selected_product,
+ 'page_format' => $default_args['page_format']
+ ) );
+ }
+
+ /**
+ * @param \Vendidero\Germanized\Shipments\Shipment $shipment
+ */
+ public function get_default_label_product( $shipment ) {
+ $country = $shipment->get_country();
+
+ if ( 'return' === $shipment->get_type() ) {
+ $country = $shipment->get_sender_country();
+ }
+
+ if ( Package::is_shipping_domestic( $country ) ) {
+ return $this->get_shipment_setting( $shipment, 'label_default_product_dom' );
+ } elseif( Package::is_eu_shipment( $country ) ) {
+ return $this->get_shipment_setting( $shipment, 'label_default_product_eu' );
+ } else {
+ return $this->get_shipment_setting( $shipment, 'label_default_product_int' );
+ }
+ }
+
+ protected function get_default_label_props( $shipment ) {
+ $dp_defaults = $this->get_default_simple_label_props( $shipment );
+ $defaults = parent::get_default_label_props( $shipment );
+ $defaults = array_replace_recursive( $defaults, $dp_defaults );
+
+ if ( ! empty( $defaults['product_id'] ) ) {
+ /**
+ * Get current services from the selected product.
+ */
+ $defaults['services'] = Package::get_internetmarke_api()->get_product_services( $defaults['product_id'] );
+
+ /**
+ * Force parent product by default to allow manually selecting services.
+ */
+ $defaults['product_id'] = Package::get_internetmarke_api()->get_product_parent_code( $defaults['product_id'] );
+ }
+
+ if ( ! empty( $defaults['product_id'] ) ) {
+ $defaults['stamp_total'] = Package::get_internetmarke_api()->get_product_total( $defaults['product_id'] );
+ }
+
+ return $defaults;
+ }
+
+ protected function get_default_simple_label_props( $shipment ) {
+ $defaults = array(
+ 'page_format' => $this->get_shipment_setting( $shipment, 'label_default_page_format' ),
+ 'stamp_total' => 0,
+ 'services' => array(),
+ );
+
+ return $defaults;
+ }
+
+ /**
+ * @param Shipment $shipment
+ *
+ * @return array
+ */
+ protected function get_default_return_label_props( $shipment ) {
+ $defaults = $this->get_default_simple_label_props( $shipment );
+ $defaults['sender_address'] = $shipment->get_address();
+
+ return $defaults;
+ }
+
+ /**
+ * @param Shipment $shipment
+ * @param $props
+ *
+ * @return \WP_Error|mixed
+ */
+ protected function validate_label_request( $shipment, $args = array() ) {
+ $args = wp_parse_args( $args, array(
+ 'page_format' => '',
+ 'product_id' => ''
+ ) );
+
+ $error = new \WP_Error();
+
+ if ( ! empty( $args['services'] ) ) {
+ /**
+ * Additional services are requested. Lets check whether the actual product exists and
+ * refresh the product code (to the child product code).
+ */
+ $im_product_code = Package::get_internetmarke_api()->get_product_code( $args['product_id'], $args['services'] );
+
+ if ( false === $im_product_code ) {
+ $error->add( 500, _x( 'The services chosen are not available for the current product.', 'dhl', 'woocommerce-germanized' ) );
+ } else {
+ $args['product_id'] = $im_product_code;
+ }
+ }
+
+ $available_products = wc_gzd_dhl_get_deutsche_post_products( $shipment, false );
+
+ /**
+ * Force the product to check to parent id because some services might not be explicitly added as
+ * available products.
+ */
+ $im_parent_code = Package::get_internetmarke_api()->get_product_parent_code( $args['product_id'] );
+
+ /**
+ * Check whether the product might not be available for the current shipment
+ */
+ if ( ! array_key_exists( $im_parent_code, $available_products ) ) {
+ /**
+ * In case no other products are available or this is a manual request - return error
+ */
+ if ( empty( $available_products ) || ( is_admin() && current_user_can( 'manage_woocommerce' ) ) ) {
+ $error->add( 500, sprintf( _x( 'Sorry but none of your selected Deutsche Post Products is available for this shipment. Please verify your shipment data (e.g. weight) and try again.', 'dhl', 'woocommerce-germanized' ), $this->get_edit_link( 'label' ) ) );
+ } else {
+ /**
+ * In case the chosen product is not available - use the first product available instead
+ * to prevent errors during automation (connected with the default product option which might not fit).
+ */
+ reset( $available_products );
+ $im_product_code = Package::get_internetmarke_api()->get_product_parent_code( key( $available_products ) );
+
+ if ( ! empty( $args['services'] ) ) {
+ $im_product_code_additional = Package::get_internetmarke_api()->get_product_code( $im_product_code, $args['services'] );
+
+ if ( false !== $im_product_code_additional ) {
+ $im_product_code = $im_product_code_additional;
+ }
+ }
+
+ $args['product_id'] = $im_product_code;
+ }
+ }
+
+ /**
+ * Refresh stamp total based on actual product.
+ */
+ if ( ! empty( $args['product_id'] ) ) {
+ $args['stamp_total'] = Package::get_internetmarke_api()->get_product_total( $args['product_id'] );
+ } else {
+ $error->add( 500, sprintf( _x( 'Deutsche Post product is missing for %s.', 'dhl', 'woocommerce-germanized' ), $shipment->get_id() ) );
+ }
+
+ if ( wc_gzd_dhl_wp_error_has_errors( $error ) ) {
+ return $error;
+ }
+
+ return $args;
+ }
+}
diff --git a/packages/woocommerce-germanized-dhl/src/ShippingProvider/ShippingMethod.php b/packages/woocommerce-germanized-dhl/src/ShippingProvider/ShippingMethod.php
new file mode 100644
index 000000000..8b034e101
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/src/ShippingProvider/ShippingMethod.php
@@ -0,0 +1,101 @@
+method = $method;
+ }
+
+ public function is_dhl_enabled() {
+ return $this->method->is_provider_enabled( 'dhl' );
+ }
+
+ public function is_deutsche_post_enabled() {
+ return $this->method->is_provider_enabled( 'deutsche_post' );
+ }
+
+ public function is_packstation_enabled() {
+ if ( $this->is_deutsche_post_enabled() ) {
+ return ParcelLocator::is_packstation_enabled( false );
+ } else {
+ return $this->method->get_option( 'dhl_parcel_pickup_packstation_enable' ) === 'yes' ? true : false;
+ }
+ }
+
+ public function is_postoffice_enabled() {
+ return $this->method->get_option( 'dhl_parcel_pickup_postoffice_enable' ) === 'yes' ? true : false;
+ }
+
+ public function is_parcelshop_enabled() {
+ return $this->method->get_option( 'dhl_parcel_pickup_parcelshop_enable' ) === 'yes' ? true : false;
+ }
+
+ public function get_enabled_preferred_services() {
+ if ( is_null( $this->preferred_services ) ) {
+ $services = wc_gzd_dhl_get_services();
+ $this->preferred_services = array();
+
+ if ( $this->is_dhl_enabled() ) {
+ foreach ( $services as $service ) {
+ if ( strpos( $service, 'Preferred' ) === false ) {
+ continue;
+ }
+
+ if ( $this->method->get_option( 'dhl_' . $service . '_enable' ) === 'yes' ) {
+ $this->preferred_services[] = $service;
+ }
+ }
+ }
+ }
+
+ return $this->preferred_services;
+ }
+
+ public function is_preferred_service_enabled( $service ) {
+ $services = $this->get_enabled_preferred_services();
+
+ return in_array( $service, $services ) && $this->is_dhl_enabled();
+ }
+
+ /**
+ * 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-dhl/templates/checkout/dhl/parcel-finder-result.php b/packages/woocommerce-germanized-dhl/templates/checkout/dhl/parcel-finder-result.php
new file mode 100644
index 000000000..19a508369
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/templates/checkout/dhl/parcel-finder-result.php
@@ -0,0 +1,49 @@
+
+
+
+
+
gzd_name; ?>
+
+
+ address->street; ?> address->streetNo; ?>
+ address->zip; ?> address->city; ?>
+
+
+ gzd_type ) : ?>
+
+
+
+ gzd_opening_hours as $time ) : ?>
+ :
+
+
+
+
+
+
+ : hasHandicappedAccess ? _x( 'Yes', 'dhl', 'woocommerce-germanized' ) : _x( 'No', 'dhl', 'woocommerce-germanized' ) ); ?>
+ : hasParkingArea ? _x( 'Yes', 'dhl', 'woocommerce-germanized' ) : _x( 'No', 'dhl', 'woocommerce-germanized' ) ); ?>
+
+
+
+
+
+
+
diff --git a/packages/woocommerce-germanized-dhl/templates/checkout/dhl/parcel-finder.php b/packages/woocommerce-germanized-dhl/templates/checkout/dhl/parcel-finder.php
new file mode 100644
index 000000000..7837cb808
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/templates/checkout/dhl/parcel-finder.php
@@ -0,0 +1,69 @@
+
+
+
diff --git a/packages/woocommerce-germanized-dhl/templates/checkout/dhl/preferred-services.php b/packages/woocommerce-germanized-dhl/templates/checkout/dhl/preferred-services.php
new file mode 100644
index 000000000..11df4cc0f
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/templates/checkout/dhl/preferred-services.php
@@ -0,0 +1,109 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/woocommerce-germanized-dhl/woocommerce-germanized-dhl.php b/packages/woocommerce-germanized-dhl/woocommerce-germanized-dhl.php
new file mode 100644
index 000000000..15aee0f43
--- /dev/null
+++ b/packages/woocommerce-germanized-dhl/woocommerce-germanized-dhl.php
@@ -0,0 +1,72 @@
+
+
+
+ composer install',
+ '' . esc_html( str_replace( ABSPATH, '', __DIR__ ) ) . '
'
+ );
+ ?>
+
+
+ .shipment-content-wrapper {
+ display: block; }
+ .germanized-shipments #panel-order-shipments .order-shipment.active > .shipment-header > .right > .handlediv .toggle-indicator::before {
+ content: "\f142"; }
+ .germanized-shipments #panel-order-shipments .order-shipment .item-count {
+ margin-right: 1em; }
+ .germanized-shipments #panel-order-shipments .order-shipment .shipment-footer {
+ margin-top: 1em; }
+ .germanized-shipments #panel-order-shipments .order-shipment .shipment-footer .shipment-footer-inner {
+ display: flex;
+ flex-wrap: nowrap;
+ justify-content: flex-end;
+ padding: 0 .5em; }
+ .germanized-shipments #panel-order-shipments .order-shipment .shipment-footer .shipment-footer-inner a.shipment-footer-action {
+ margin-right: 1em; }
+ .germanized-shipments #panel-order-shipments .order-shipment .shipment-footer .shipment-footer-inner a.shipment-footer-action:last-child {
+ margin-right: 0; }
+ .germanized-shipments #panel-order-shipments .order-shipment .shipment-header {
+ color: #999;
+ background: #f8f8f8;
+ margin: 1.5em 0;
+ padding: .5em 1em;
+ cursor: pointer; }
+ .germanized-shipments #panel-order-shipments .order-shipment .shipment-header .shipment-status {
+ margin-left: 1em; }
+ .germanized-shipments #panel-order-shipments .order-shipment .shipment-header h3 {
+ margin: 0; }
+ .germanized-shipments #panel-order-shipments .order-shipment:first-child .shipment-header {
+ margin-top: 0; }
+ .germanized-shipments #panel-order-shipments .order-shipment.active > .shipment-header, .germanized-shipments #panel-order-shipments .order-shipment .shipment-header:hover {
+ background: #f3f3f3; }
+ .germanized-shipments #panel-order-shipments .order-shipment .shipment-content-wrapper {
+ display: none; }
+ .germanized-shipments #panel-order-shipments .order-shipment .shipment-content {
+ padding: 1em;
+ margin-top: -1.5em;
+ padding-bottom: 0; }
+ .germanized-shipments #panel-order-shipments .order-shipment .add-shipment-return {
+ display: none; }
+ .germanized-shipments #panel-order-shipments .order-shipment.is-returnable .add-shipment-return {
+ display: block; }
+ .germanized-shipments #panel-order-shipments .order-shipment p.form-row {
+ margin-bottom: 1.5em; }
+ .germanized-shipments #panel-order-shipments .order-shipment p.form-row.wc-gzd-shipment-packaging-wrapper {
+ margin-top: 0; }
+ .germanized-shipments #panel-order-shipments .order-shipment p.form-row input[type=text], .germanized-shipments #panel-order-shipments .order-shipment p.form-row input[type=number], .germanized-shipments #panel-order-shipments .order-shipment p.form-row input[type=email] {
+ height: 30px; }
+ .germanized-shipments #panel-order-shipments .order-shipment p.form-row select {
+ line-height: 30px;
+ height: 30px;
+ padding-top: 0;
+ padding-bottom: 0; }
+ .germanized-shipments #panel-order-shipments .order-shipment p.form-row label {
+ color: #999;
+ font-weight: 600; }
+ .germanized-shipments #panel-order-shipments .order-shipment p.form-row label .woocommerce-help-tip {
+ float: none; }
+ .germanized-shipments #panel-order-shipments .order-shipment .columns .column.column-spaced {
+ margin: 5px 0; }
+ .germanized-shipments #panel-order-shipments .order-shipment .columns .column h4 {
+ margin-bottom: .7em;
+ color: #999; }
+ .germanized-shipments #panel-order-shipments .order-shipment .columns .column h4 a {
+ color: #999;
+ text-decoration: none; }
+ .germanized-shipments #panel-order-shipments .order-shipment .shipment-items .shipment-item-list-wrapper .shipment-item-action {
+ text-align: right; }
+ .germanized-shipments #panel-order-shipments .order-shipment .shipment-items .shipment-item-list-wrapper .shipment-item-quantity input {
+ width: 50px;
+ text-align: center; }
+ .germanized-shipments #panel-order-shipments .order-shipment .shipment-items .shipment-item-list-wrapper .shipment-item-name p.form-row {
+ margin-bottom: 0;
+ margin-top: .5em; }
+ .germanized-shipments #panel-order-shipments .order-shipment .shipment-items .shipment-item-list-wrapper .shipment-item-heading {
+ padding: .5em;
+ color: #999;
+ background: #f8f8f8;
+ font-weight: 600; }
+ .germanized-shipments #panel-order-shipments .order-shipment .shipment-items .shipment-item-list-wrapper .shipment-item {
+ padding: .5em;
+ border-bottom: 1px solid #dfdfdf; }
+ .germanized-shipments #panel-order-shipments .order-shipment .shipment-items .shipment-item-list-wrapper .shipment-item:last-child {
+ border-bottom: none; }
+ .germanized-shipments #panel-order-shipments .order-shipment .shipment-items .shipment-item-list-wrapper .shipment-item:nth-child(2n) {
+ background: #f8f8f8; }
+ .germanized-shipments #panel-order-shipments .order-shipment .shipment-items .shipment-item-list-wrapper .shipment-item .columns {
+ align-items: center; }
+ .germanized-shipments #panel-order-shipments .order-shipment .shipment-item-actions {
+ display: flex;
+ padding: .7em .5em;
+ flex-wrap: nowrap;
+ justify-content: flex-end;
+ border-top: 1px solid #dfdfdf; }
+ .germanized-shipments #panel-order-shipments .order-shipment .shipment-item-actions .add-items {
+ margin-right: 1em; }
+ .germanized-shipments #panel-order-shipments .order-shipment .shipment-item-actions .woocommerce-help-tip {
+ margin-left: 0; }
+ .germanized-shipments #panel-order-shipments .order-shipment .add-items {
+ display: none; }
+ .germanized-shipments #panel-order-shipments .order-shipment .shipment-returns {
+ margin-top: .5em; }
+ .germanized-shipments #panel-order-shipments .order-shipment .shipment-returns .shipment-return .shipment-header {
+ background: transparent;
+ border-bottom: 1px solid #dfdfdf;
+ padding-left: 0;
+ padding-right: 0; }
+ .germanized-shipments #panel-order-shipments .order-shipment .shipment-returns .shipment-return .shipment-header h3 {
+ font-size: 1.1em; }
+ .germanized-shipments #panel-order-shipments .order-shipment .shipment-returns .shipment-return .shipment-content {
+ padding: 1em 0; }
+ .germanized-shipments #panel-order-shipments .order-shipment.needs-items .add-items {
+ display: block; }
+ .germanized-shipments #panel-order-shipments .form-row .input-inner-wrap {
+ clear: left;
+ margin: 0;
+ display: flex;
+ flex-wrap: nowrap; }
+ .germanized-shipments #panel-order-shipments .form-row .input-inner-wrap input {
+ margin-right: 1em; }
+ .germanized-shipments #panel-order-shipments .form-row .input-inner-wrap input:last-child {
+ margin-right: 0; }
+
+.germanized-shipments .title-spread {
+ display: flex;
+ flex-wrap: nowrap;
+ justify-content: space-between;
+ align-items: center; }
+ .germanized-shipments .title-spread .right, .germanized-shipments .title-spread .left {
+ display: inline-flex;
+ align-items: center; }
+
+.germanized-shipments .show-xs,
+.germanized-shipments .show-sm,
+.germanized-shipments .show-md,
+.germanized-shipments .show-lg,
+.germanized-shipments .show-xl {
+ display: none !important; }
+
+.germanized-shipments .columns {
+ display: flex;
+ flex-wrap: wrap;
+ margin-left: -1rem;
+ margin-right: -1rem; }
+ .germanized-shipments .columns.col-gapless {
+ margin-left: 0;
+ margin-right: 0; }
+ .germanized-shipments .columns.col-gapless > .column {
+ padding-left: 0;
+ padding-right: 0; }
+ .germanized-shipments .columns.col-oneline {
+ flex-wrap: nowrap;
+ overflow-x: auto; }
+
+.germanized-shipments .column {
+ flex: 1;
+ max-width: 100%;
+ padding-left: 1rem;
+ padding-right: 1rem; }
+ .germanized-shipments .column.col-12, .germanized-shipments .column.col-11, .germanized-shipments .column.col-10, .germanized-shipments .column.col-9, .germanized-shipments .column.col-8, .germanized-shipments .column.col-7, .germanized-shipments .column.col-6, .germanized-shipments .column.col-5, .germanized-shipments .column.col-4, .germanized-shipments .column.col-3, .germanized-shipments .column.col-2, .germanized-shipments .column.col-1, .germanized-shipments .column.col-auto {
+ flex: none; }
+
+.germanized-shipments .col-12 {
+ width: 100%; }
+
+.germanized-shipments .col-11 {
+ width: 91.66666667%; }
+
+.germanized-shipments .col-10 {
+ width: 83.33333333%; }
+
+.germanized-shipments .col-9 {
+ width: 75%; }
+
+.germanized-shipments .col-8 {
+ width: 66.66666667%; }
+
+.germanized-shipments .col-7 {
+ width: 58.33333333%; }
+
+.germanized-shipments .col-6 {
+ width: 50%; }
+
+.germanized-shipments .col-5 {
+ width: 41.66666667%; }
+
+.germanized-shipments .col-4 {
+ width: 33.33333333%; }
+
+.germanized-shipments .col-3 {
+ width: 25%; }
+
+.germanized-shipments .col-2 {
+ width: 16.66666667%; }
+
+.germanized-shipments .col-1 {
+ width: 8.33333333%; }
+
+.germanized-shipments .col-auto {
+ flex: 0 0 auto;
+ max-width: none;
+ width: auto; }
+
+.germanized-shipments .col-mx-auto {
+ margin-left: auto;
+ margin-right: auto; }
+
+.germanized-shipments .col-ml-auto {
+ margin-left: auto; }
+
+.germanized-shipments .col-mr-auto {
+ margin-right: auto; }
+
+@media (max-width: 1280px) {
+ .germanized-shipments .col-xl-12,
+ .germanized-shipments .col-xl-11,
+ .germanized-shipments .col-xl-10,
+ .germanized-shipments .col-xl-9,
+ .germanized-shipments .col-xl-8,
+ .germanized-shipments .col-xl-7,
+ .germanized-shipments .col-xl-6,
+ .germanized-shipments .col-xl-5,
+ .germanized-shipments .col-xl-4,
+ .germanized-shipments .col-xl-3,
+ .germanized-shipments .col-xl-2,
+ .germanized-shipments .col-xl-1,
+ .germanized-shipments .col-xl-auto {
+ flex: none; }
+ .germanized-shipments .col-xl-12 {
+ width: 100%; }
+ .germanized-shipments .col-xl-11 {
+ width: 91.66666667%; }
+ .germanized-shipments .col-xl-10 {
+ width: 83.33333333%; }
+ .germanized-shipments .col-xl-9 {
+ width: 75%; }
+ .germanized-shipments .col-xl-8 {
+ width: 66.66666667%; }
+ .germanized-shipments .col-xl-7 {
+ width: 58.33333333%; }
+ .germanized-shipments .col-xl-6 {
+ width: 50%; }
+ .germanized-shipments .col-xl-5 {
+ width: 41.66666667%; }
+ .germanized-shipments .col-xl-4 {
+ width: 33.33333333%; }
+ .germanized-shipments .col-xl-3 {
+ width: 25%; }
+ .germanized-shipments .col-xl-2 {
+ width: 16.66666667%; }
+ .germanized-shipments .col-xl-1 {
+ width: 8.33333333%; }
+ .germanized-shipments .col-xl-auto {
+ width: auto; }
+ .germanized-shipments .hide-xl {
+ display: none !important; }
+ .germanized-shipments .show-xl {
+ display: block !important; } }
+
+@media (max-width: 960px) {
+ .germanized-shipments .col-lg-12,
+ .germanized-shipments .col-lg-11,
+ .germanized-shipments .col-lg-10,
+ .germanized-shipments .col-lg-9,
+ .germanized-shipments .col-lg-8,
+ .germanized-shipments .col-lg-7,
+ .germanized-shipments .col-lg-6,
+ .germanized-shipments .col-lg-5,
+ .germanized-shipments .col-lg-4,
+ .germanized-shipments .col-lg-3,
+ .germanized-shipments .col-lg-2,
+ .germanized-shipments .col-lg-1,
+ .germanized-shipments .col-lg-auto {
+ flex: none; }
+ .germanized-shipments .col-lg-12 {
+ width: 100%; }
+ .germanized-shipments .col-lg-11 {
+ width: 91.66666667%; }
+ .germanized-shipments .col-lg-10 {
+ width: 83.33333333%; }
+ .germanized-shipments .col-lg-9 {
+ width: 75%; }
+ .germanized-shipments .col-lg-8 {
+ width: 66.66666667%; }
+ .germanized-shipments .col-lg-7 {
+ width: 58.33333333%; }
+ .germanized-shipments .col-lg-6 {
+ width: 50%; }
+ .germanized-shipments .col-lg-5 {
+ width: 41.66666667%; }
+ .germanized-shipments .col-lg-4 {
+ width: 33.33333333%; }
+ .germanized-shipments .col-lg-3 {
+ width: 25%; }
+ .germanized-shipments .col-lg-2 {
+ width: 16.66666667%; }
+ .germanized-shipments .col-lg-1 {
+ width: 8.33333333%; }
+ .germanized-shipments .col-lg-auto {
+ width: auto; }
+ .germanized-shipments .hide-lg {
+ display: none !important; }
+ .germanized-shipments .show-lg {
+ display: block !important; } }
+
+@media (max-width: 840px) {
+ .germanized-shipments .col-md-12,
+ .germanized-shipments .col-md-11,
+ .germanized-shipments .col-md-10,
+ .germanized-shipments .col-md-9,
+ .germanized-shipments .col-md-8,
+ .germanized-shipments .col-md-7,
+ .germanized-shipments .col-md-6,
+ .germanized-shipments .col-md-5,
+ .germanized-shipments .col-md-4,
+ .germanized-shipments .col-md-3,
+ .germanized-shipments .col-md-2,
+ .germanized-shipments .col-md-1,
+ .germanized-shipments .col-md-auto {
+ flex: none; }
+ .germanized-shipments .col-md-12 {
+ width: 100%; }
+ .germanized-shipments .col-md-11 {
+ width: 91.66666667%; }
+ .germanized-shipments .col-md-10 {
+ width: 83.33333333%; }
+ .germanized-shipments .col-md-9 {
+ width: 75%; }
+ .germanized-shipments .col-md-8 {
+ width: 66.66666667%; }
+ .germanized-shipments .col-md-7 {
+ width: 58.33333333%; }
+ .germanized-shipments .col-md-6 {
+ width: 50%; }
+ .germanized-shipments .col-md-5 {
+ width: 41.66666667%; }
+ .germanized-shipments .col-md-4 {
+ width: 33.33333333%; }
+ .germanized-shipments .col-md-3 {
+ width: 25%; }
+ .germanized-shipments .col-md-2 {
+ width: 16.66666667%; }
+ .germanized-shipments .col-md-1 {
+ width: 8.33333333%; }
+ .germanized-shipments .col-md-auto {
+ width: auto; }
+ .germanized-shipments .hide-md {
+ display: none !important; }
+ .germanized-shipments .show-md {
+ display: block !important; } }
+
+@media (max-width: 600px) {
+ .germanized-shipments .col-sm-12,
+ .germanized-shipments .col-sm-11,
+ .germanized-shipments .col-sm-10,
+ .germanized-shipments .col-sm-9,
+ .germanized-shipments .col-sm-8,
+ .germanized-shipments .col-sm-7,
+ .germanized-shipments .col-sm-6,
+ .germanized-shipments .col-sm-5,
+ .germanized-shipments .col-sm-4,
+ .germanized-shipments .col-sm-3,
+ .germanized-shipments .col-sm-2,
+ .germanized-shipments .col-sm-1,
+ .germanized-shipments .col-sm-auto {
+ flex: none; }
+ .germanized-shipments .col-sm-12 {
+ width: 100%; }
+ .germanized-shipments .col-sm-11 {
+ width: 91.66666667%; }
+ .germanized-shipments .col-sm-10 {
+ width: 83.33333333%; }
+ .germanized-shipments .col-sm-9 {
+ width: 75%; }
+ .germanized-shipments .col-sm-8 {
+ width: 66.66666667%; }
+ .germanized-shipments .col-sm-7 {
+ width: 58.33333333%; }
+ .germanized-shipments .col-sm-6 {
+ width: 50%; }
+ .germanized-shipments .col-sm-5 {
+ width: 41.66666667%; }
+ .germanized-shipments .col-sm-4 {
+ width: 33.33333333%; }
+ .germanized-shipments .col-sm-3 {
+ width: 25%; }
+ .germanized-shipments .col-sm-2 {
+ width: 16.66666667%; }
+ .germanized-shipments .col-sm-1 {
+ width: 8.33333333%; }
+ .germanized-shipments .col-sm-auto {
+ width: auto; }
+ .germanized-shipments .hide-sm {
+ display: none !important; }
+ .germanized-shipments .show-sm {
+ display: block !important; } }
+
+@media (max-width: 480px) {
+ .germanized-shipments .col-xs-12,
+ .germanized-shipments .col-xs-11,
+ .germanized-shipments .col-xs-10,
+ .germanized-shipments .col-xs-9,
+ .germanized-shipments .col-xs-8,
+ .germanized-shipments .col-xs-7,
+ .germanized-shipments .col-xs-6,
+ .germanized-shipments .col-xs-5,
+ .germanized-shipments .col-xs-4,
+ .germanized-shipments .col-xs-3,
+ .germanized-shipments .col-xs-2,
+ .germanized-shipments .col-xs-1,
+ .germanized-shipments .col-xs-auto {
+ flex: none; }
+ .germanized-shipments .col-xs-12 {
+ width: 100%; }
+ .germanized-shipments .col-xs-11 {
+ width: 91.66666667%; }
+ .germanized-shipments .col-xs-10 {
+ width: 83.33333333%; }
+ .germanized-shipments .col-xs-9 {
+ width: 75%; }
+ .germanized-shipments .col-xs-8 {
+ width: 66.66666667%; }
+ .germanized-shipments .col-xs-7 {
+ width: 58.33333333%; }
+ .germanized-shipments .col-xs-6 {
+ width: 50%; }
+ .germanized-shipments .col-xs-5 {
+ width: 41.66666667%; }
+ .germanized-shipments .col-xs-4 {
+ width: 33.33333333%; }
+ .germanized-shipments .col-xs-3 {
+ width: 25%; }
+ .germanized-shipments .col-xs-2 {
+ width: 16.66666667%; }
+ .germanized-shipments .col-xs-1 {
+ width: 8.33333333%; }
+ .germanized-shipments .col-xs-auto {
+ width: auto; }
+ .germanized-shipments .hide-xs {
+ display: none !important; }
+ .germanized-shipments .show-xs {
+ display: block !important; } }
\ No newline at end of file
diff --git a/packages/woocommerce-germanized-shipments/assets/css/admin.min.css b/packages/woocommerce-germanized-shipments/assets/css/admin.min.css
new file mode 100644
index 000000000..86e90e769
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/assets/css/admin.min.css
@@ -0,0 +1 @@
+.wc-modal-shipping-method-settings .form-table td .wc-gzd-additional-desc{margin-top:1em;line-height:1.5em;background:#efefef;padding:.5em;font-style:normal;font-size:13px;box-shadow:0 1px 1px 0 rgba(0,0,0,.1)}.germanized-create-label .notice-wrapper .notice{margin:0;margin-bottom:1em}.germanized-create-label .notice-wrapper .notice p{margin:.5em 0!important;padding:2px!important;font-size:13px;line-height:1.5}.germanized-create-label p.form-field{margin-bottom:5px!important;margin-top:5px!important}.germanized-create-label p.form-field:first-child,.germanized-create-label p.form-field:last-child{margin-bottom:5px!important;margin-top:5px!important}.germanized-create-label p.form-field:not(.column){display:inline-block;width:100%}.germanized-create-label .columns{margin-left:-.5rem!important;margin-right:-.5rem!important}.germanized-create-label .column{padding-left:.5rem!important;padding-right:.5rem!important}.germanized-create-label .hide-default,.germanized-create-label .show-if{display:none}.germanized-create-label .show-if label{color:#777}.germanized-create-label p.form-field label{width:100%;display:block;margin-bottom:5px;font-weight:700}.germanized-create-label p.form-field input[type=email],.germanized-create-label p.form-field input[type=text],.germanized-create-label p.form-field select{width:100%;max-width:100%}.germanized-create-label p.form-field.form-field-checkbox{display:flex;flex-wrap:wrap;flex-direction:row;justify-content:flex-start;margin-top:10px!important;margin-bottom:10px!important;align-items:center}.germanized-create-label p.form-field.form-field-checkbox label{width:auto;margin-left:.5em;font-weight:400;order:2;margin-bottom:0}.germanized-create-label p.form-field.form-field-checkbox input[type=checkbox]{order:1}.germanized-create-label p.form-field.form-field-checkbox .woocommerce-help-tip{order:3;margin-left:3px}.germanized-create-label p.form-field.form-field-checkbox .description{width:100%;margin-top:5px;color:#777;order:4;font-style:normal}table.wc-gzd-shipping-providers{margin-top:1.5em}table.wc-gzd-shipping-providers td,table.wc-gzd-shipping-providers th{display:table-cell!important;padding:1em!important;vertical-align:top;line-height:1.75em;font-size:14px}table.wc-gzd-shipping-providers th{font-weight:600}table.wc-gzd-shipping-providers td.wc-gzd-shipping-provider-activated,table.wc-gzd-shipping-providers th.wc-gzd-shipping-provider-activated{width:1%;text-align:center}table.wc-gzd-shipping-providers td.wc-gzd-shipping-provider-activated .status-disabled,table.wc-gzd-shipping-providers td.wc-gzd-shipping-provider-activated .status-enabled,table.wc-gzd-shipping-providers th.wc-gzd-shipping-provider-activated .status-disabled,table.wc-gzd-shipping-providers th.wc-gzd-shipping-provider-activated .status-enabled{display:inline-block;margin-top:3px}table.wc-gzd-shipping-providers td.wc-gzd-shipping-provider-actions,table.wc-gzd-shipping-providers th.wc-gzd-shipping-provider-actions{width:15%;text-align:right}table.wc-gzd-shipping-providers td.wc-gzd-shipping-provider-actions{display:flex;justify-content:flex-end;flex-wrap:wrap}table.wc-gzd-shipping-providers td.wc-gzd-shipping-provider-actions .button{margin-right:5px}table.wc-gzd-shipping-providers td.wc-gzd-shipping-provider-actions .button:last-child{margin-right:0}table.wc-gzd-shipping-providers td.wc-gzd-shipping-provider-title,table.wc-gzd-shipping-providers th.wc-gzd-shipping-provider-title{width:30ch}table.wc-gzd-shipping-providers tr:nth-child(odd) td{background:#f9f9f9}.order-return-status,.order-shipping-status,.shipment-status{background:#eee;padding:.2em .5em;font-size:.9em;border-radius:3px;display:inline-flex;white-space:nowrap}.order-return-status.status-draft,.order-return-status.status-open,.order-return-status.status-partially-returned,.order-return-status.status-partially-shipped,.order-return-status.status-processing,.order-return-status.status-requested,.order-shipping-status.status-draft,.order-shipping-status.status-open,.order-shipping-status.status-partially-returned,.order-shipping-status.status-partially-shipped,.order-shipping-status.status-processing,.order-shipping-status.status-requested,.shipment-status.status-draft,.shipment-status.status-open,.shipment-status.status-partially-returned,.shipment-status.status-partially-shipped,.shipment-status.status-processing,.shipment-status.status-requested{background:#f8dda7;color:#94660c}.order-return-status.status-not-shipped,.order-shipping-status.status-not-shipped,.shipment-status.status-not-shipped{background:#eba3a3;color:#761919}.order-return-status.status-delivered,.order-return-status.status-returned,.order-return-status.status-shipped,.order-shipping-status.status-delivered,.order-shipping-status.status-returned,.order-shipping-status.status-shipped,.shipment-status.status-delivered,.shipment-status.status-returned,.shipment-status.status-shipped{background:#c6e1c6;color:#5b841b}.order-return-status.shipment-type-return-status.status-shipped,.order-shipping-status.shipment-type-return-status.status-shipped,.shipment-status.shipment-type-return-status.status-shipped{background:#f8dda7;color:#94660c}.woocommerce_page_wc-gzd-return-shipments .tablenav .actions,.woocommerce_page_wc-gzd-shipments .tablenav .actions{overflow:visible}.woocommerce_page_wc-gzd-return-shipments .tablenav .select2-container,.woocommerce_page_wc-gzd-shipments .tablenav .select2-container{float:left;width:240px!important;font-size:14px;vertical-align:middle;margin:1px 6px 4px 1px}.woocommerce_page_wc-gzd-return-shipments .tablenav .select2-container .select2-selection--single,.woocommerce_page_wc-gzd-shipments .tablenav .select2-container .select2-selection--single{height:32px}.woocommerce_page_wc-gzd-return-shipments .tablenav .select2-container .select2-selection--single .select2-selection__rendered,.woocommerce_page_wc-gzd-shipments .tablenav .select2-container .select2-selection--single .select2-selection__rendered{line-height:29px}.woocommerce_page_wc-gzd-return-shipments .tablenav .select2-container .select2-selection--single .select2-selection__arrow,.woocommerce_page_wc-gzd-shipments .tablenav .select2-container .select2-selection--single .select2-selection__arrow{height:30px}.woocommerce_page_wc-gzd-return-shipments .tablenav input,.woocommerce_page_wc-gzd-return-shipments .tablenav select,.woocommerce_page_wc-gzd-shipments .tablenav input,.woocommerce_page_wc-gzd-shipments .tablenav select{line-height:1;height:32px}.woocommerce_page_wc-gzd-return-shipments .tablenav input,.woocommerce_page_wc-gzd-shipments .tablenav input{height:31px}.woocommerce_page_wc-gzd-return-shipments .tablenav #shipment-query-submit,.woocommerce_page_wc-gzd-shipments .tablenav #shipment-query-submit{margin:1px 8px 0 0}.woocommerce_page_wc-gzd-return-shipments #posts-filter .bulk-action-wrapper,.woocommerce_page_wc-gzd-shipments #posts-filter .bulk-action-wrapper{display:none;clear:both;margin:1em 0;float:left;width:50%}.woocommerce_page_wc-gzd-return-shipments #posts-filter .bulk-action-wrapper h4,.woocommerce_page_wc-gzd-shipments #posts-filter .bulk-action-wrapper h4{margin-top:0}.woocommerce_page_wc-gzd-return-shipments #posts-filter .bulk-action-wrapper progress,.woocommerce_page_wc-gzd-shipments #posts-filter .bulk-action-wrapper progress{width:100%;height:42px;margin:0 auto;display:block;-webkit-appearance:none;border:none;background:#f5f5f5;border:2px solid #eee;border-radius:4px;padding:0;box-shadow:0 1px 0 0 rgba(255,255,255,.2)}.woocommerce_page_wc-gzd-return-shipments #posts-filter .bulk-action-wrapper progress::-webkit-progress-bar,.woocommerce_page_wc-gzd-shipments #posts-filter .bulk-action-wrapper progress::-webkit-progress-bar{background:transparent none;border:0;border-radius:4px;padding:0;box-shadow:none}.woocommerce_page_wc-gzd-return-shipments #posts-filter .bulk-action-wrapper progress::-webkit-progress-value,.woocommerce_page_wc-gzd-shipments #posts-filter .bulk-action-wrapper progress::-webkit-progress-value{border-radius:3px;box-shadow:inset 0 1px 1px 0 rgba(255,255,255,.4);background:#a46497;background:linear-gradient(to bottom,#a46497,#66405f),#a46497;transition:width 1s ease}.woocommerce_page_wc-gzd-return-shipments #posts-filter .bulk-action-wrapper progress::-moz-progress-bar,.woocommerce_page_wc-gzd-shipments #posts-filter .bulk-action-wrapper progress::-moz-progress-bar{border-radius:3px;box-shadow:inset 0 1px 1px 0 rgba(255,255,255,.4);background:#a46497;background:linear-gradient(to bottom,#a46497,#66405f),#a46497;transition:width 1s ease}.woocommerce_page_wc-gzd-return-shipments #posts-filter .bulk-action-wrapper progress::-ms-fill,.woocommerce_page_wc-gzd-shipments #posts-filter .bulk-action-wrapper progress::-ms-fill{border-radius:3px;box-shadow:inset 0 1px 1px 0 rgba(255,255,255,.4);background:#a46497;background:linear-gradient(to bottom,#a46497,#66405f),#a46497;transition:width 1s ease}.woocommerce_page_wc-gzd-return-shipments #posts-filter.bulk-action-processing .bulk-action-wrapper,.woocommerce_page_wc-gzd-shipments #posts-filter.bulk-action-processing .bulk-action-wrapper{display:block}.woocommerce_page_wc-gzd-return-shipments .wp-list-table,.woocommerce_page_wc-gzd-shipments .wp-list-table{margin-top:1em}.woocommerce_page_wc-gzd-return-shipments .wp-list-table td,.woocommerce_page_wc-gzd-return-shipments .wp-list-table th,.woocommerce_page_wc-gzd-shipments .wp-list-table td,.woocommerce_page_wc-gzd-shipments .wp-list-table th{padding:.5em 1em;width:10ch;vertical-align:middle}.woocommerce_page_wc-gzd-return-shipments .wp-list-table tbody th,.woocommerce_page_wc-gzd-return-shipments .wp-list-table td,.woocommerce_page_wc-gzd-shipments .wp-list-table tbody th,.woocommerce_page_wc-gzd-shipments .wp-list-table td{line-height:26px}.woocommerce_page_wc-gzd-return-shipments .wp-list-table thead th,.woocommerce_page_wc-gzd-shipments .wp-list-table thead th{padding:.5em 1em}.woocommerce_page_wc-gzd-return-shipments .wp-list-table thead th.sortable a,.woocommerce_page_wc-gzd-return-shipments .wp-list-table thead th.sorted a,.woocommerce_page_wc-gzd-shipments .wp-list-table thead th.sortable a,.woocommerce_page_wc-gzd-shipments .wp-list-table thead th.sorted a{padding:0}.woocommerce_page_wc-gzd-return-shipments .wp-list-table thead th:last-child,.woocommerce_page_wc-gzd-shipments .wp-list-table thead th:last-child{padding-right:2em}.woocommerce_page_wc-gzd-return-shipments .wp-list-table .check-column,.woocommerce_page_wc-gzd-shipments .wp-list-table .check-column{width:16px;white-space:nowrap;padding:1em 1em 1em 1em!important;vertical-align:middle}.woocommerce_page_wc-gzd-return-shipments .wp-list-table .check-column input,.woocommerce_page_wc-gzd-shipments .wp-list-table .check-column input{vertical-align:text-top;margin:1px 0}.woocommerce_page_wc-gzd-return-shipments .wp-list-table td.column-title,.woocommerce_page_wc-gzd-shipments .wp-list-table td.column-title{font-weight:700}.woocommerce_page_wc-gzd-return-shipments .wp-list-table td.column-title .shipment-title-meta,.woocommerce_page_wc-gzd-shipments .wp-list-table td.column-title .shipment-title-meta{margin-top:0;font-weight:400;color:#999;font-size:12px}.woocommerce_page_wc-gzd-return-shipments .wp-list-table td.column-title .shipment-title-meta .shipment-tracking-id,.woocommerce_page_wc-gzd-shipments .wp-list-table td.column-title .shipment-title-meta .shipment-tracking-id{color:#999;display:block}.woocommerce_page_wc-gzd-return-shipments .wp-list-table .column-title,.woocommerce_page_wc-gzd-shipments .wp-list-table .column-title{width:20ch}.woocommerce_page_wc-gzd-return-shipments .wp-list-table .column-actions,.woocommerce_page_wc-gzd-shipments .wp-list-table .column-actions{width:10ch}.woocommerce_page_wc-gzd-return-shipments .wp-list-table .column-order,.woocommerce_page_wc-gzd-shipments .wp-list-table .column-order{width:10ch}.woocommerce_page_wc-gzd-return-shipments .wp-list-table .column-address a,.woocommerce_page_wc-gzd-return-shipments .wp-list-table .column-sender a,.woocommerce_page_wc-gzd-shipments .wp-list-table .column-address a,.woocommerce_page_wc-gzd-shipments .wp-list-table .column-sender a{color:#32373c}.woocommerce_page_wc-gzd-return-shipments .wp-list-table .shipment-status,.woocommerce_page_wc-gzd-shipments .wp-list-table .shipment-status{font-size:1em}.woocommerce_page_wc-gzd-return-shipments .wp-list-table .column-actions,.woocommerce_page_wc-gzd-shipments .wp-list-table .column-actions{text-align:right}.woocommerce_page_wc-gzd-return-shipments .wp-list-table .column-actions a.button,.woocommerce_page_wc-gzd-shipments .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_wc-gzd-return-shipments .wp-list-table .column-actions a.button::after,.woocommerce_page_wc-gzd-shipments .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_wc-gzd-return-shipments .wp-list-table .column-actions a.button.processing::after,.woocommerce_page_wc-gzd-shipments .wp-list-table .column-actions a.button.processing::after{font-family:WooCommerce;content:"\e00f"}.woocommerce_page_wc-gzd-return-shipments .wp-list-table .column-actions a.button.shipped::after,.woocommerce_page_wc-gzd-shipments .wp-list-table .column-actions a.button.shipped::after{content:"\f147"}.woocommerce_page_wc-gzd-return-shipments .wp-list-table .column-actions a.button.delivered::after,.woocommerce_page_wc-gzd-shipments .wp-list-table .column-actions a.button.delivered::after{content:"\f147"}.woocommerce_page_wc-gzd-return-shipments .wp-list-table .column-actions a.button.confirm::after,.woocommerce_page_wc-gzd-shipments .wp-list-table .column-actions a.button.confirm::after{content:"\f147"}.woocommerce_page_wc-gzd-return-shipments .wp-list-table .column-actions a.button.generate::after,.woocommerce_page_wc-gzd-shipments .wp-list-table .column-actions a.button.generate::after{content:"\f502"}.woocommerce_page_wc-gzd-return-shipments .wp-list-table .column-actions a.button.download::after,.woocommerce_page_wc-gzd-shipments .wp-list-table .column-actions a.button.download::after{content:"\f103"}.woocommerce_page_wc-gzd-return-shipments .wp-list-table .column-address,.woocommerce_page_wc-gzd-return-shipments .wp-list-table .column-sender,.woocommerce_page_wc-gzd-shipments .wp-list-table .column-address,.woocommerce_page_wc-gzd-shipments .wp-list-table .column-sender{width:20ch}.woocommerce_page_wc-gzd-return-shipments .wp-list-table .column-items,.woocommerce_page_wc-gzd-shipments .wp-list-table .column-items{width:20ch}.woocommerce_page_wc-gzd-return-shipments .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview,.woocommerce_page_wc-gzd-shipments .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview{font-size:.9em;border-spacing:0}.woocommerce_page_wc-gzd-return-shipments .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview thead th,.woocommerce_page_wc-gzd-shipments .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_wc-gzd-return-shipments .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview tr td,.woocommerce_page_wc-gzd-shipments .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview tr td{border-bottom:1px solid #ccc!important}.woocommerce_page_wc-gzd-return-shipments .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview tr:last-child td,.woocommerce_page_wc-gzd-shipments .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview tr:last-child td{border-bottom:none!important}.woocommerce_page_wc-gzd-return-shipments .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview td,.woocommerce_page_wc-gzd-return-shipments .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview th,.woocommerce_page_wc-gzd-shipments .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview td,.woocommerce_page_wc-gzd-shipments .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview th{padding:.3em 0;vertical-align:top;line-height:20px}.woocommerce_page_wc-gzd-return-shipments .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview td.wc-gzd-shipment-item-column-name,.woocommerce_page_wc-gzd-return-shipments .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview th.wc-gzd-shipment-item-column-name,.woocommerce_page_wc-gzd-shipments .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview td.wc-gzd-shipment-item-column-name,.woocommerce_page_wc-gzd-shipments .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview th.wc-gzd-shipment-item-column-name{width:70%}.woocommerce_page_wc-gzd-return-shipments .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview td.wc-gzd-shipment-item-column-name small,.woocommerce_page_wc-gzd-return-shipments .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview th.wc-gzd-shipment-item-column-name small,.woocommerce_page_wc-gzd-shipments .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview td.wc-gzd-shipment-item-column-name small,.woocommerce_page_wc-gzd-shipments .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_wc-gzd-return-shipments .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview td.wc-gzd-shipment-item-column-quantity,.woocommerce_page_wc-gzd-return-shipments .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview th.wc-gzd-shipment-item-column-quantity,.woocommerce_page_wc-gzd-shipments .wp-list-table #the-list .column-items table.wc-gzd-shipments-preview td.wc-gzd-shipment-item-column-quantity,.woocommerce_page_wc-gzd-shipments .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}#woocommerce-gzd-order-shipments .inside{margin:0;padding:0;display:block!important}#woocommerce-gzd-order-shipments .handlediv,#woocommerce-gzd-order-shipments .hndle,#woocommerce-gzd-order-shipments .postbox-header{display:none}#woocommerce-gzd-order-shipments .hide-default{display:none}.germanized-shipments *{box-sizing:border-box}.germanized-shipments #panel-order-shipments{padding:23px 0 0}.germanized-shipments #panel-order-shipments .panel-inner{padding:0 24px}.germanized-shipments #panel-order-shipments .panel-title-inner{padding-left:0;margin-top:1em;padding-right:0}.germanized-shipments #panel-order-shipments .panel-title{margin-bottom:1.5em}.germanized-shipments #panel-order-shipments .panel-title h2{margin:0;font-family:HelveticaNeue-Light,"Helvetica Neue Light","Helvetica Neue",sans-serif;font-size:21px;font-weight:400;line-height:1.2;text-shadow:1px 1px 1px #fff;padding:0}.germanized-shipments #panel-order-shipments .panel-footer{background:#f8f8f8;padding-top:1em;padding-bottom:1em;border-top:1px solid #dfdfdf;display:none}.germanized-shipments #panel-order-shipments .panel-footer .order-shipments-actions{display:flex;flex-wrap:nowrap;justify-content:space-between}.germanized-shipments #panel-order-shipments .panel-footer .order-shipments-actions .shipment-actions-left{display:flex;flex-wrap:wrap;justify-content:flex-start}.germanized-shipments #panel-order-shipments .panel-footer .order-shipments-actions .shipment-actions-left .button{margin-right:1em}.germanized-shipments #panel-order-shipments .panel-footer #order-shipments-save{display:none}.germanized-shipments #panel-order-shipments #order-return-shipment-add,.germanized-shipments #panel-order-shipments #order-shipment-add{display:none}.germanized-shipments #panel-order-shipments.needs-shipments .panel-footer{display:block}.germanized-shipments #panel-order-shipments.needs-shipments #order-shipment-add{display:block}.germanized-shipments #panel-order-shipments.needs-returns .panel-footer{display:block}.germanized-shipments #panel-order-shipments.needs-returns #order-return-shipment-add{display:block}.germanized-shipments #panel-order-shipments #order-shipments-list{margin-bottom:1.5em}.germanized-shipments #panel-order-shipments .delete{color:#a00}.germanized-shipments #panel-order-shipments .delete:hover{color:#dc3232;border:none}.germanized-shipments #panel-order-shipments .order-shipment a .woocommerce-help-tip{margin-right:3px}.germanized-shipments #panel-order-shipments .order-shipment .handlediv{display:inline-block;float:none;width:auto;height:auto}.germanized-shipments #panel-order-shipments .order-shipment .handlediv .toggle-indicator::before{content:"\f140"}.germanized-shipments #panel-order-shipments .order-shipment .wc-gzd-shipment-label h4{margin-top:0}.germanized-shipments #panel-order-shipments .order-shipment .wc-gzd-shipment-label .shipment-label-actions .shipment-label-actions-wrapper{display:flex;flex-wrap:wrap;justify-content:flex-start;margin-bottom:1em;align-items:center}.germanized-shipments #panel-order-shipments .order-shipment .wc-gzd-shipment-label .shipment-label-actions .shipment-label-actions-wrapper a{margin-right:1em}.germanized-shipments #panel-order-shipments .order-shipment .show-if{display:none}.germanized-shipments #panel-order-shipments .order-shipment.active>.shipment-content-wrapper{display:block}.germanized-shipments #panel-order-shipments .order-shipment.active>.shipment-header>.right>.handlediv .toggle-indicator::before{content:"\f142"}.germanized-shipments #panel-order-shipments .order-shipment .item-count{margin-right:1em}.germanized-shipments #panel-order-shipments .order-shipment .shipment-footer{margin-top:1em}.germanized-shipments #panel-order-shipments .order-shipment .shipment-footer .shipment-footer-inner{display:flex;flex-wrap:nowrap;justify-content:flex-end;padding:0 .5em}.germanized-shipments #panel-order-shipments .order-shipment .shipment-footer .shipment-footer-inner a.shipment-footer-action{margin-right:1em}.germanized-shipments #panel-order-shipments .order-shipment .shipment-footer .shipment-footer-inner a.shipment-footer-action:last-child{margin-right:0}.germanized-shipments #panel-order-shipments .order-shipment .shipment-header{color:#999;background:#f8f8f8;margin:1.5em 0;padding:.5em 1em;cursor:pointer}.germanized-shipments #panel-order-shipments .order-shipment .shipment-header .shipment-status{margin-left:1em}.germanized-shipments #panel-order-shipments .order-shipment .shipment-header h3{margin:0}.germanized-shipments #panel-order-shipments .order-shipment:first-child .shipment-header{margin-top:0}.germanized-shipments #panel-order-shipments .order-shipment .shipment-header:hover,.germanized-shipments #panel-order-shipments .order-shipment.active>.shipment-header{background:#f3f3f3}.germanized-shipments #panel-order-shipments .order-shipment .shipment-content-wrapper{display:none}.germanized-shipments #panel-order-shipments .order-shipment .shipment-content{padding:1em;margin-top:-1.5em;padding-bottom:0}.germanized-shipments #panel-order-shipments .order-shipment .add-shipment-return{display:none}.germanized-shipments #panel-order-shipments .order-shipment.is-returnable .add-shipment-return{display:block}.germanized-shipments #panel-order-shipments .order-shipment p.form-row{margin-bottom:1.5em}.germanized-shipments #panel-order-shipments .order-shipment p.form-row.wc-gzd-shipment-packaging-wrapper{margin-top:0}.germanized-shipments #panel-order-shipments .order-shipment p.form-row input[type=email],.germanized-shipments #panel-order-shipments .order-shipment p.form-row input[type=number],.germanized-shipments #panel-order-shipments .order-shipment p.form-row input[type=text]{height:30px}.germanized-shipments #panel-order-shipments .order-shipment p.form-row select{line-height:30px;height:30px;padding-top:0;padding-bottom:0}.germanized-shipments #panel-order-shipments .order-shipment p.form-row label{color:#999;font-weight:600}.germanized-shipments #panel-order-shipments .order-shipment p.form-row label .woocommerce-help-tip{float:none}.germanized-shipments #panel-order-shipments .order-shipment .columns .column.column-spaced{margin:5px 0}.germanized-shipments #panel-order-shipments .order-shipment .columns .column h4{margin-bottom:.7em;color:#999}.germanized-shipments #panel-order-shipments .order-shipment .columns .column h4 a{color:#999;text-decoration:none}.germanized-shipments #panel-order-shipments .order-shipment .shipment-items .shipment-item-list-wrapper .shipment-item-action{text-align:right}.germanized-shipments #panel-order-shipments .order-shipment .shipment-items .shipment-item-list-wrapper .shipment-item-quantity input{width:50px;text-align:center}.germanized-shipments #panel-order-shipments .order-shipment .shipment-items .shipment-item-list-wrapper .shipment-item-name p.form-row{margin-bottom:0;margin-top:.5em}.germanized-shipments #panel-order-shipments .order-shipment .shipment-items .shipment-item-list-wrapper .shipment-item-heading{padding:.5em;color:#999;background:#f8f8f8;font-weight:600}.germanized-shipments #panel-order-shipments .order-shipment .shipment-items .shipment-item-list-wrapper .shipment-item{padding:.5em;border-bottom:1px solid #dfdfdf}.germanized-shipments #panel-order-shipments .order-shipment .shipment-items .shipment-item-list-wrapper .shipment-item:last-child{border-bottom:none}.germanized-shipments #panel-order-shipments .order-shipment .shipment-items .shipment-item-list-wrapper .shipment-item:nth-child(2n){background:#f8f8f8}.germanized-shipments #panel-order-shipments .order-shipment .shipment-items .shipment-item-list-wrapper .shipment-item .columns{align-items:center}.germanized-shipments #panel-order-shipments .order-shipment .shipment-item-actions{display:flex;padding:.7em .5em;flex-wrap:nowrap;justify-content:flex-end;border-top:1px solid #dfdfdf}.germanized-shipments #panel-order-shipments .order-shipment .shipment-item-actions .add-items{margin-right:1em}.germanized-shipments #panel-order-shipments .order-shipment .shipment-item-actions .woocommerce-help-tip{margin-left:0}.germanized-shipments #panel-order-shipments .order-shipment .add-items{display:none}.germanized-shipments #panel-order-shipments .order-shipment .shipment-returns{margin-top:.5em}.germanized-shipments #panel-order-shipments .order-shipment .shipment-returns .shipment-return .shipment-header{background:0 0;border-bottom:1px solid #dfdfdf;padding-left:0;padding-right:0}.germanized-shipments #panel-order-shipments .order-shipment .shipment-returns .shipment-return .shipment-header h3{font-size:1.1em}.germanized-shipments #panel-order-shipments .order-shipment .shipment-returns .shipment-return .shipment-content{padding:1em 0}.germanized-shipments #panel-order-shipments .order-shipment.needs-items .add-items{display:block}.germanized-shipments #panel-order-shipments .form-row .input-inner-wrap{clear:left;margin:0;display:flex;flex-wrap:nowrap}.germanized-shipments #panel-order-shipments .form-row .input-inner-wrap input{margin-right:1em}.germanized-shipments #panel-order-shipments .form-row .input-inner-wrap input:last-child{margin-right:0}.germanized-shipments .title-spread{display:flex;flex-wrap:nowrap;justify-content:space-between;align-items:center}.germanized-shipments .title-spread .left,.germanized-shipments .title-spread .right{display:inline-flex;align-items:center}.germanized-shipments .show-lg,.germanized-shipments .show-md,.germanized-shipments .show-sm,.germanized-shipments .show-xl,.germanized-shipments .show-xs{display:none!important}.germanized-shipments .columns{display:flex;flex-wrap:wrap;margin-left:-1rem;margin-right:-1rem}.germanized-shipments .columns.col-gapless{margin-left:0;margin-right:0}.germanized-shipments .columns.col-gapless>.column{padding-left:0;padding-right:0}.germanized-shipments .columns.col-oneline{flex-wrap:nowrap;overflow-x:auto}.germanized-shipments .column{flex:1;max-width:100%;padding-left:1rem;padding-right:1rem}.germanized-shipments .column.col-1,.germanized-shipments .column.col-10,.germanized-shipments .column.col-11,.germanized-shipments .column.col-12,.germanized-shipments .column.col-2,.germanized-shipments .column.col-3,.germanized-shipments .column.col-4,.germanized-shipments .column.col-5,.germanized-shipments .column.col-6,.germanized-shipments .column.col-7,.germanized-shipments .column.col-8,.germanized-shipments .column.col-9,.germanized-shipments .column.col-auto{flex:none}.germanized-shipments .col-12{width:100%}.germanized-shipments .col-11{width:91.66666667%}.germanized-shipments .col-10{width:83.33333333%}.germanized-shipments .col-9{width:75%}.germanized-shipments .col-8{width:66.66666667%}.germanized-shipments .col-7{width:58.33333333%}.germanized-shipments .col-6{width:50%}.germanized-shipments .col-5{width:41.66666667%}.germanized-shipments .col-4{width:33.33333333%}.germanized-shipments .col-3{width:25%}.germanized-shipments .col-2{width:16.66666667%}.germanized-shipments .col-1{width:8.33333333%}.germanized-shipments .col-auto{flex:0 0 auto;max-width:none;width:auto}.germanized-shipments .col-mx-auto{margin-left:auto;margin-right:auto}.germanized-shipments .col-ml-auto{margin-left:auto}.germanized-shipments .col-mr-auto{margin-right:auto}@media (max-width:1280px){.germanized-shipments .col-xl-1,.germanized-shipments .col-xl-10,.germanized-shipments .col-xl-11,.germanized-shipments .col-xl-12,.germanized-shipments .col-xl-2,.germanized-shipments .col-xl-3,.germanized-shipments .col-xl-4,.germanized-shipments .col-xl-5,.germanized-shipments .col-xl-6,.germanized-shipments .col-xl-7,.germanized-shipments .col-xl-8,.germanized-shipments .col-xl-9,.germanized-shipments .col-xl-auto{flex:none}.germanized-shipments .col-xl-12{width:100%}.germanized-shipments .col-xl-11{width:91.66666667%}.germanized-shipments .col-xl-10{width:83.33333333%}.germanized-shipments .col-xl-9{width:75%}.germanized-shipments .col-xl-8{width:66.66666667%}.germanized-shipments .col-xl-7{width:58.33333333%}.germanized-shipments .col-xl-6{width:50%}.germanized-shipments .col-xl-5{width:41.66666667%}.germanized-shipments .col-xl-4{width:33.33333333%}.germanized-shipments .col-xl-3{width:25%}.germanized-shipments .col-xl-2{width:16.66666667%}.germanized-shipments .col-xl-1{width:8.33333333%}.germanized-shipments .col-xl-auto{width:auto}.germanized-shipments .hide-xl{display:none!important}.germanized-shipments .show-xl{display:block!important}}@media (max-width:960px){.germanized-shipments .col-lg-1,.germanized-shipments .col-lg-10,.germanized-shipments .col-lg-11,.germanized-shipments .col-lg-12,.germanized-shipments .col-lg-2,.germanized-shipments .col-lg-3,.germanized-shipments .col-lg-4,.germanized-shipments .col-lg-5,.germanized-shipments .col-lg-6,.germanized-shipments .col-lg-7,.germanized-shipments .col-lg-8,.germanized-shipments .col-lg-9,.germanized-shipments .col-lg-auto{flex:none}.germanized-shipments .col-lg-12{width:100%}.germanized-shipments .col-lg-11{width:91.66666667%}.germanized-shipments .col-lg-10{width:83.33333333%}.germanized-shipments .col-lg-9{width:75%}.germanized-shipments .col-lg-8{width:66.66666667%}.germanized-shipments .col-lg-7{width:58.33333333%}.germanized-shipments .col-lg-6{width:50%}.germanized-shipments .col-lg-5{width:41.66666667%}.germanized-shipments .col-lg-4{width:33.33333333%}.germanized-shipments .col-lg-3{width:25%}.germanized-shipments .col-lg-2{width:16.66666667%}.germanized-shipments .col-lg-1{width:8.33333333%}.germanized-shipments .col-lg-auto{width:auto}.germanized-shipments .hide-lg{display:none!important}.germanized-shipments .show-lg{display:block!important}}@media (max-width:840px){.germanized-shipments .col-md-1,.germanized-shipments .col-md-10,.germanized-shipments .col-md-11,.germanized-shipments .col-md-12,.germanized-shipments .col-md-2,.germanized-shipments .col-md-3,.germanized-shipments .col-md-4,.germanized-shipments .col-md-5,.germanized-shipments .col-md-6,.germanized-shipments .col-md-7,.germanized-shipments .col-md-8,.germanized-shipments .col-md-9,.germanized-shipments .col-md-auto{flex:none}.germanized-shipments .col-md-12{width:100%}.germanized-shipments .col-md-11{width:91.66666667%}.germanized-shipments .col-md-10{width:83.33333333%}.germanized-shipments .col-md-9{width:75%}.germanized-shipments .col-md-8{width:66.66666667%}.germanized-shipments .col-md-7{width:58.33333333%}.germanized-shipments .col-md-6{width:50%}.germanized-shipments .col-md-5{width:41.66666667%}.germanized-shipments .col-md-4{width:33.33333333%}.germanized-shipments .col-md-3{width:25%}.germanized-shipments .col-md-2{width:16.66666667%}.germanized-shipments .col-md-1{width:8.33333333%}.germanized-shipments .col-md-auto{width:auto}.germanized-shipments .hide-md{display:none!important}.germanized-shipments .show-md{display:block!important}}@media (max-width:600px){.germanized-shipments .col-sm-1,.germanized-shipments .col-sm-10,.germanized-shipments .col-sm-11,.germanized-shipments .col-sm-12,.germanized-shipments .col-sm-2,.germanized-shipments .col-sm-3,.germanized-shipments .col-sm-4,.germanized-shipments .col-sm-5,.germanized-shipments .col-sm-6,.germanized-shipments .col-sm-7,.germanized-shipments .col-sm-8,.germanized-shipments .col-sm-9,.germanized-shipments .col-sm-auto{flex:none}.germanized-shipments .col-sm-12{width:100%}.germanized-shipments .col-sm-11{width:91.66666667%}.germanized-shipments .col-sm-10{width:83.33333333%}.germanized-shipments .col-sm-9{width:75%}.germanized-shipments .col-sm-8{width:66.66666667%}.germanized-shipments .col-sm-7{width:58.33333333%}.germanized-shipments .col-sm-6{width:50%}.germanized-shipments .col-sm-5{width:41.66666667%}.germanized-shipments .col-sm-4{width:33.33333333%}.germanized-shipments .col-sm-3{width:25%}.germanized-shipments .col-sm-2{width:16.66666667%}.germanized-shipments .col-sm-1{width:8.33333333%}.germanized-shipments .col-sm-auto{width:auto}.germanized-shipments .hide-sm{display:none!important}.germanized-shipments .show-sm{display:block!important}}@media (max-width:480px){.germanized-shipments .col-xs-1,.germanized-shipments .col-xs-10,.germanized-shipments .col-xs-11,.germanized-shipments .col-xs-12,.germanized-shipments .col-xs-2,.germanized-shipments .col-xs-3,.germanized-shipments .col-xs-4,.germanized-shipments .col-xs-5,.germanized-shipments .col-xs-6,.germanized-shipments .col-xs-7,.germanized-shipments .col-xs-8,.germanized-shipments .col-xs-9,.germanized-shipments .col-xs-auto{flex:none}.germanized-shipments .col-xs-12{width:100%}.germanized-shipments .col-xs-11{width:91.66666667%}.germanized-shipments .col-xs-10{width:83.33333333%}.germanized-shipments .col-xs-9{width:75%}.germanized-shipments .col-xs-8{width:66.66666667%}.germanized-shipments .col-xs-7{width:58.33333333%}.germanized-shipments .col-xs-6{width:50%}.germanized-shipments .col-xs-5{width:41.66666667%}.germanized-shipments .col-xs-4{width:33.33333333%}.germanized-shipments .col-xs-3{width:25%}.germanized-shipments .col-xs-2{width:16.66666667%}.germanized-shipments .col-xs-1{width:8.33333333%}.germanized-shipments .col-xs-auto{width:auto}.germanized-shipments .hide-xs{display:none!important}.germanized-shipments .show-xs{display:block!important}}
\ No newline at end of file
diff --git a/packages/woocommerce-germanized-shipments/assets/css/admin.scss b/packages/woocommerce-germanized-shipments/assets/css/admin.scss
new file mode 100644
index 000000000..882bfb4fd
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/assets/css/admin.scss
@@ -0,0 +1,1318 @@
+@import '../../node_modules/spectre.css/src/variables';
+
+$layout-spacing: 1rem;
+
+.wc-modal-shipping-method-settings .form-table td .wc-gzd-additional-desc {
+ margin-top: 1em;
+ line-height: 1.5em;
+ background: #efefef;
+ padding: .5em;
+ font-style: normal;
+ font-size: 13px;
+ box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1);
+}
+
+.germanized-create-label {
+ .notice-wrapper {
+ .notice {
+ margin: 0;
+ margin-bottom: 1em;
+
+ p {
+ margin: 0.5em 0 !important;
+ padding: 2px !important;
+ font-size: 13px;
+ line-height: 1.5;
+ }
+ }
+ }
+
+ p.form-field {
+ &:first-child, &:last-child {
+ margin-bottom: 5px !important;
+ margin-top: 5px !important;
+ }
+ &:not(.column) {
+ display: inline-block;
+ width: 100%;
+ }
+
+ margin-bottom: 5px !important;
+ margin-top: 5px !important;
+ }
+
+ .columns {
+ margin-left: -.5rem !important;
+ margin-right: -.5rem !important;
+ }
+
+ .column {
+ padding-left: .5rem !important;
+ padding-right: .5rem !important;
+ }
+
+ .show-if, .hide-default {
+ display: none;
+ }
+
+ .show-if {
+ label {
+ color: #777;
+ }
+ }
+
+ p.form-field {
+ label {
+ width: 100%;
+ display: block;
+ margin-bottom: 5px;
+ font-weight: bold;
+ }
+ select, input[type=text], input[type=email] {
+ width: 100%;
+ max-width: 100%;
+ }
+
+ &.form-field-checkbox {
+ display: flex;
+ flex-wrap: wrap;
+ flex-direction: row;
+ justify-content: flex-start;
+ margin-top: 10px !important;
+ margin-bottom: 10px !important;
+ align-items: center;
+
+ label {
+ width: auto;
+ margin-left: .5em;
+ font-weight: normal;
+ order: 2;
+ margin-bottom: 0;
+ }
+
+ input[type=checkbox] {
+ order: 1;
+ }
+
+ .woocommerce-help-tip {
+ order: 3;
+ margin-left: 3px;
+ }
+
+ .description {
+ width: 100%;
+ margin-top: 5px;
+ color: #777;
+ order: 4;
+ font-style: normal;
+ }
+ }
+ }
+}
+
+table.wc-gzd-shipping-providers {
+ margin-top: 1.5em;
+
+ th, td {
+ display: table-cell !important;
+ padding: 1em !important;
+ vertical-align: top;
+ line-height: 1.75em;
+ font-size: 14px;
+ }
+
+ th {
+ font-weight: 600;
+ }
+
+ td.wc-gzd-shipping-provider-activated, th.wc-gzd-shipping-provider-activated {
+ width: 1%;
+ text-align: center;
+
+ .status-disabled, .status-enabled {
+ display: inline-block;
+ margin-top: 3px;
+ }
+ }
+
+ td.wc-gzd-shipping-provider-actions, th.wc-gzd-shipping-provider-actions {
+ width: 15%;
+ text-align: right;
+ }
+
+ td.wc-gzd-shipping-provider-actions {
+ display: flex;
+ justify-content: flex-end;
+ flex-wrap: wrap;
+
+ .button {
+ margin-right: 5px;
+
+ &:last-child {
+ margin-right: 0;
+ }
+ }
+ }
+
+ td.wc-gzd-shipping-provider-title, th.wc-gzd-shipping-provider-title {
+ width: 30ch;
+ }
+
+ tr:nth-child(odd) td {
+ background: #f9f9f9;
+ }
+}
+
+.shipment-status, .order-shipping-status, .order-return-status {
+ background: #eee;
+ padding: .2em .5em;
+ font-size: .9em;
+ border-radius: 3px;
+ display: inline-flex;
+ white-space: nowrap;
+
+ &.status-draft, &.status-processing, &.status-requested, &.status-partially-shipped, &.status-open, &.status-partially-returned {
+ background: #f8dda7;
+ color: #94660c;
+ }
+
+ &.status-not-shipped {
+ background: #eba3a3;
+ color: #761919;
+ }
+
+ &.status-delivered, &.status-shipped, &.status-shipped, &.status-returned {
+ background: #c6e1c6;
+ color: #5b841b;
+ }
+
+ &.shipment-type-return-status.status-shipped {
+ background: #f8dda7;
+ color: #94660c;
+ }
+}
+
+.woocommerce_page_wc-gzd-shipments, .woocommerce_page_wc-gzd-return-shipments {
+
+ .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;
+ }
+
+ #shipment-query-submit {
+ margin: 1px 8px 0 0;
+ }
+ }
+
+ #posts-filter {
+ .bulk-action-wrapper {
+ display: none;
+ clear: both;
+ margin: 1em 0;
+ float: left;
+ width: 50%;
+
+ h4 {
+ margin-top: 0;
+ }
+
+ progress {
+ width: 100%;
+ height: 42px;
+ margin: 0 auto;
+ display: block;
+ -webkit-appearance: none;
+ border: none;
+ background: #f5f5f5;
+ border: 2px solid #eee;
+ border-radius: 4px;
+ padding: 0;
+ box-shadow: 0 1px 0 0 rgba(255, 255, 255, 0.2);
+ }
+
+ progress::-webkit-progress-bar {
+ background: transparent none;
+ border: 0;
+ border-radius: 4px;
+ padding: 0;
+ box-shadow: none;
+ }
+
+ progress::-webkit-progress-value {
+ border-radius: 3px;
+ box-shadow: inset 0 1px 1px 0 rgba(255, 255, 255, 0.4);
+ background: #a46497;
+ background: linear-gradient(to bottom, #a46497, #66405f), #a46497;
+ transition: width 1s ease;
+ }
+
+ progress::-moz-progress-bar {
+ border-radius: 3px;
+ box-shadow: inset 0 1px 1px 0 rgba(255, 255, 255, 0.4);
+ background: #a46497;
+ background: linear-gradient(to bottom, #a46497, #66405f), #a46497;
+ transition: width 1s ease;
+ }
+
+ progress::-ms-fill {
+ border-radius: 3px;
+ box-shadow: inset 0 1px 1px 0 rgba(255, 255, 255, 0.4);
+ background: #a46497;
+ background: linear-gradient(to bottom, #a46497, #66405f), #a46497;
+ transition: width 1s ease;
+ }
+ }
+
+ &.bulk-action-processing {
+ .bulk-action-wrapper {
+ display: block;
+ }
+ }
+ }
+
+ .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;
+
+ .shipment-title-meta {
+ margin-top: 0;
+ font-weight: normal;
+ color: #999;
+ font-size: 12px;
+
+ .shipment-tracking-id {
+ color: #999;
+ display: block;
+ }
+ }
+ }
+
+ .column-title {
+ width: 20ch;
+ }
+
+ .column-actions {
+ width: 10ch;
+ }
+
+ .column-order {
+ width: 10ch;
+ }
+
+ .column-address, .column-sender {
+ a {
+ color: #32373c;
+ }
+ }
+
+ .shipment-status {
+ font-size: 1em;
+ }
+
+ .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;
+ }
+
+ &.processing::after {
+ font-family: WooCommerce;
+ content: "\e00f";
+ }
+
+ &.shipped::after {
+ content: "\f147";
+ }
+
+ &.delivered::after {
+ content: "\f147";
+ }
+
+ &.confirm::after {
+ content: "\f147";
+ }
+
+ &.generate::after {
+ content: "\f502";
+ }
+
+ &.download::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;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+#woocommerce-gzd-order-shipments {
+ .inside {
+ margin: 0;
+ padding: 0;
+ display: block !important;
+ }
+
+ .hndle, .handlediv, .postbox-header {
+ display: none;
+ }
+
+ .hide-default {
+ display: none;
+ }
+}
+
+.germanized-shipments {
+ * {
+ box-sizing: border-box;
+ }
+
+ #panel-order-shipments {
+ padding: 23px 0 0;
+
+ .panel-inner {
+ padding: 0 24px;
+ }
+
+ .panel-title-inner {
+ padding-left: 0;
+ margin-top: 1em;
+ padding-right: 0;
+ }
+
+ .panel-title {
+ h2 {
+ margin: 0;
+ font-family: HelveticaNeue-Light,"Helvetica Neue Light","Helvetica Neue",sans-serif;
+ font-size: 21px;
+ font-weight: 400;
+ line-height: 1.2;
+ text-shadow: 1px 1px 1px #fff;
+ padding: 0;
+ }
+
+ margin-bottom: 1.5em;
+ }
+
+ .panel-footer {
+ background: #f8f8f8;
+ padding-top: 1em;
+ padding-bottom: 1em;
+ border-top: 1px solid #dfdfdf;
+ display: none;
+
+ .order-shipments-actions {
+ display: flex;
+ flex-wrap: nowrap;
+ justify-content: space-between;
+
+ .shipment-actions-left {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: flex-start;
+
+ .button {
+ margin-right: 1em;
+ }
+ }
+ }
+
+ #order-shipments-save {
+ display: none;
+ }
+ }
+
+ #order-shipment-add, #order-return-shipment-add {
+ display: none;
+ }
+
+ &.needs-shipments {
+ .panel-footer {
+ display: block;
+ }
+ #order-shipment-add {
+ display: block;
+ }
+ }
+
+ &.needs-returns {
+ .panel-footer {
+ display: block;
+ }
+ #order-return-shipment-add {
+ display: block;
+ }
+ }
+
+ #order-shipments-list {
+ margin-bottom: 1.5em;
+ }
+
+ .delete {
+ color: #a00;
+
+ &:hover {
+ color: #dc3232;
+ border: none;
+ }
+ }
+
+ .order-shipment {
+ a {
+ .woocommerce-help-tip {
+ margin-right: 3px;
+ }
+ }
+ .handlediv {
+ display: inline-block;
+ float: none;
+ width: auto;
+ height: auto;
+ .toggle-indicator {
+ &::before {
+ content: "\f140";
+ }
+ }
+ }
+
+ .wc-gzd-shipment-label {
+ h4 {
+ margin-top: 0;
+ }
+
+ .shipment-label-actions {
+ .shipment-label-actions-wrapper {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: flex-start;
+ margin-bottom: 1em;
+ align-items: center;
+
+ a {
+ margin-right: 1em;
+ }
+ }
+ }
+ }
+
+ .show-if {
+ display: none;
+ }
+
+ &.active {
+ > .shipment-content-wrapper {
+ display: block;
+ }
+
+ > .shipment-header > .right > .handlediv .toggle-indicator {
+ &::before {
+ content: "\f142";
+ }
+ }
+ }
+
+ .item-count {
+ margin-right: 1em;
+ }
+
+ .shipment-footer {
+ margin-top: 1em;
+
+ .shipment-footer-inner {
+ display: flex;
+ flex-wrap: nowrap;
+ justify-content: flex-end;
+ padding: 0 .5em;
+
+ a.shipment-footer-action {
+ margin-right: 1em;
+
+ &:last-child {
+ margin-right: 0;
+ }
+ }
+ }
+ }
+
+ .shipment-header {
+ color: #999;
+ background: #f8f8f8;
+ margin: 1.5em 0;
+ padding: .5em 1em;
+ cursor: pointer;
+
+ .shipment-status {
+ margin-left: 1em;
+ }
+
+ h3 {
+ margin: 0;
+ }
+ }
+
+ &:first-child {
+ .shipment-header {
+ margin-top: 0;
+ }
+ }
+
+ &.active > .shipment-header, .shipment-header:hover {
+ background: darken(#f8f8f8, 2%);
+ }
+
+ .shipment-content-wrapper {
+ display: none;
+ }
+
+ .shipment-content {
+ padding: 1em;
+ margin-top: -1.5em;
+ padding-bottom: 0;
+ }
+
+ .add-shipment-return {
+ display: none;
+ }
+
+ &.is-returnable {
+ .add-shipment-return {
+ display: block;
+ }
+ }
+
+ p.form-row {
+ margin-bottom: 1.5em;
+
+ &.wc-gzd-shipment-packaging-wrapper {
+ margin-top: 0;
+ }
+
+ input[type=text], input[type=number], input[type=email] {
+ height: 30px;
+ }
+
+ select {
+ line-height: 30px;
+ height: 30px;
+ padding-top: 0;
+ padding-bottom: 0;
+ }
+
+ label {
+ color: #999;
+ font-weight: 600;
+
+ .woocommerce-help-tip {
+ float: none;
+ }
+ }
+ }
+
+ .columns {
+ .column {
+ &.column-spaced {
+ margin: 5px 0;
+ }
+
+ h4 {
+ margin-bottom: .7em;
+ color: #999;
+
+ a {
+ color: #999;
+ text-decoration: none;
+ }
+ }
+ }
+ }
+
+ .column-shipment-documents {
+
+ }
+
+ .shipment-items {
+ .shipment-item-list-wrapper {
+ .shipment-item-action {
+ text-align: right;
+ }
+
+ .shipment-item-quantity {
+ input {
+ width: 50px;
+ text-align: center;
+ }
+ }
+
+ .shipment-item-name {
+ p.form-row {
+ margin-bottom: 0;
+ margin-top: .5em;
+ }
+ }
+
+ .shipment-item-heading {
+ padding: .5em;
+ color: #999;
+ background: #f8f8f8;
+ font-weight: 600;
+ }
+
+ .shipment-item {
+ padding: .5em;
+ border-bottom: 1px solid #dfdfdf;
+
+ &:last-child {
+ border-bottom: none;
+ }
+
+ &:nth-child(2n) {
+ background: #f8f8f8;
+ }
+
+ .columns {
+ align-items: center;
+ }
+ }
+ }
+ }
+
+ .shipment-item-actions {
+ display: flex;
+ padding: .7em .5em;
+ flex-wrap: nowrap;
+ justify-content: flex-end;
+ border-top: 1px solid #dfdfdf;
+
+ .add-items {
+ margin-right: 1em;
+ }
+
+ .woocommerce-help-tip {
+ margin-left: 0;
+ }
+ }
+
+ .add-items {
+ display: none;
+ }
+
+ .shipment-returns {
+ margin-top: .5em;
+
+ .shipment-return {
+ .shipment-header {
+ background: transparent;
+ border-bottom: 1px solid #dfdfdf;
+ padding-left: 0;
+ padding-right: 0;
+
+ h3 {
+ font-size: 1.1em;
+ }
+ }
+
+ .shipment-content {
+ padding: 1em 0;
+ }
+ }
+ }
+
+ &.needs-items {
+ .add-items {
+ display: block;
+ }
+ }
+ }
+
+ .form-row {
+ .input-inner-wrap {
+ clear: left;
+ margin: 0;
+ display: flex;
+ flex-wrap: nowrap;
+
+ input {
+ margin-right: 1em;
+
+ &:last-child {
+ margin-right: 0;
+ }
+ }
+ }
+ }
+ }
+
+ .title-spread {
+ display: flex;
+ flex-wrap: nowrap;
+ justify-content: space-between;
+ align-items: center;
+
+ .right, .left {
+ display: inline-flex;
+ align-items: center;
+ }
+ }
+
+ // Responsive breakpoint system
+ .show-xs,
+ .show-sm,
+ .show-md,
+ .show-lg,
+ .show-xl {
+ display: none !important;
+ }
+
+ // Responsive grid system
+ .columns {
+ display: flex;
+ flex-wrap: wrap;
+ margin-left: -$layout-spacing;
+ margin-right: -$layout-spacing;
+
+ &.col-gapless {
+ margin-left: 0;
+ margin-right: 0;
+
+ & > .column {
+ padding-left: 0;
+ padding-right: 0;
+ }
+ }
+ &.col-oneline {
+ flex-wrap: nowrap;
+ overflow-x: auto;
+ }
+ }
+ .column {
+ flex: 1;
+ max-width: 100%;
+ padding-left: $layout-spacing;
+ padding-right: $layout-spacing;
+
+ &.col-12,
+ &.col-11,
+ &.col-10,
+ &.col-9,
+ &.col-8,
+ &.col-7,
+ &.col-6,
+ &.col-5,
+ &.col-4,
+ &.col-3,
+ &.col-2,
+ &.col-1,
+ &.col-auto {
+ flex: none;
+ }
+ }
+ .col-12 {
+ width: 100%;
+ }
+ .col-11 {
+ width: 91.66666667%;
+ }
+ .col-10 {
+ width: 83.33333333%;
+ }
+ .col-9 {
+ width: 75%;
+ }
+ .col-8 {
+ width: 66.66666667%;
+ }
+ .col-7 {
+ width: 58.33333333%;
+ }
+ .col-6 {
+ width: 50%;
+ }
+ .col-5 {
+ width: 41.66666667%;
+ }
+ .col-4 {
+ width: 33.33333333%;
+ }
+ .col-3 {
+ width: 25%;
+ }
+ .col-2 {
+ width: 16.66666667%;
+ }
+ .col-1 {
+ width: 8.33333333%;
+ }
+ .col-auto {
+ flex: 0 0 auto;
+ max-width: none;
+ width: auto;
+ }
+ .col-mx-auto {
+ margin-left: auto;
+ margin-right: auto;
+ }
+ .col-ml-auto {
+ margin-left: auto;
+ }
+ .col-mr-auto {
+ margin-right: auto;
+ }
+ @media (max-width: $size-xl) {
+ .col-xl-12,
+ .col-xl-11,
+ .col-xl-10,
+ .col-xl-9,
+ .col-xl-8,
+ .col-xl-7,
+ .col-xl-6,
+ .col-xl-5,
+ .col-xl-4,
+ .col-xl-3,
+ .col-xl-2,
+ .col-xl-1,
+ .col-xl-auto {
+ flex: none;
+ }
+ .col-xl-12 {
+ width: 100%;
+ }
+ .col-xl-11 {
+ width: 91.66666667%;
+ }
+ .col-xl-10 {
+ width: 83.33333333%;
+ }
+ .col-xl-9 {
+ width: 75%;
+ }
+ .col-xl-8 {
+ width: 66.66666667%;
+ }
+ .col-xl-7 {
+ width: 58.33333333%;
+ }
+ .col-xl-6 {
+ width: 50%;
+ }
+ .col-xl-5 {
+ width: 41.66666667%;
+ }
+ .col-xl-4 {
+ width: 33.33333333%;
+ }
+ .col-xl-3 {
+ width: 25%;
+ }
+ .col-xl-2 {
+ width: 16.66666667%;
+ }
+ .col-xl-1 {
+ width: 8.33333333%;
+ }
+ .col-xl-auto {
+ width: auto;
+ }
+ .hide-xl {
+ display: none !important;
+ }
+ .show-xl {
+ display: block !important;
+ }
+ }
+ @media (max-width: $size-lg) {
+ .col-lg-12,
+ .col-lg-11,
+ .col-lg-10,
+ .col-lg-9,
+ .col-lg-8,
+ .col-lg-7,
+ .col-lg-6,
+ .col-lg-5,
+ .col-lg-4,
+ .col-lg-3,
+ .col-lg-2,
+ .col-lg-1,
+ .col-lg-auto {
+ flex: none;
+ }
+ .col-lg-12 {
+ width: 100%;
+ }
+ .col-lg-11 {
+ width: 91.66666667%;
+ }
+ .col-lg-10 {
+ width: 83.33333333%;
+ }
+ .col-lg-9 {
+ width: 75%;
+ }
+ .col-lg-8 {
+ width: 66.66666667%;
+ }
+ .col-lg-7 {
+ width: 58.33333333%;
+ }
+ .col-lg-6 {
+ width: 50%;
+ }
+ .col-lg-5 {
+ width: 41.66666667%;
+ }
+ .col-lg-4 {
+ width: 33.33333333%;
+ }
+ .col-lg-3 {
+ width: 25%;
+ }
+ .col-lg-2 {
+ width: 16.66666667%;
+ }
+ .col-lg-1 {
+ width: 8.33333333%;
+ }
+ .col-lg-auto {
+ width: auto;
+ }
+ .hide-lg {
+ display: none !important;
+ }
+ .show-lg {
+ display: block !important;
+ }
+ }
+ @media (max-width: $size-md) {
+ .col-md-12,
+ .col-md-11,
+ .col-md-10,
+ .col-md-9,
+ .col-md-8,
+ .col-md-7,
+ .col-md-6,
+ .col-md-5,
+ .col-md-4,
+ .col-md-3,
+ .col-md-2,
+ .col-md-1,
+ .col-md-auto {
+ flex: none;
+ }
+ .col-md-12 {
+ width: 100%;
+ }
+ .col-md-11 {
+ width: 91.66666667%;
+ }
+ .col-md-10 {
+ width: 83.33333333%;
+ }
+ .col-md-9 {
+ width: 75%;
+ }
+ .col-md-8 {
+ width: 66.66666667%;
+ }
+ .col-md-7 {
+ width: 58.33333333%;
+ }
+ .col-md-6 {
+ width: 50%;
+ }
+ .col-md-5 {
+ width: 41.66666667%;
+ }
+ .col-md-4 {
+ width: 33.33333333%;
+ }
+ .col-md-3 {
+ width: 25%;
+ }
+ .col-md-2 {
+ width: 16.66666667%;
+ }
+ .col-md-1 {
+ width: 8.33333333%;
+ }
+ .col-md-auto {
+ width: auto;
+ }
+ .hide-md {
+ display: none !important;
+ }
+ .show-md {
+ display: block !important;
+ }
+ }
+ @media (max-width: $size-sm) {
+ .col-sm-12,
+ .col-sm-11,
+ .col-sm-10,
+ .col-sm-9,
+ .col-sm-8,
+ .col-sm-7,
+ .col-sm-6,
+ .col-sm-5,
+ .col-sm-4,
+ .col-sm-3,
+ .col-sm-2,
+ .col-sm-1,
+ .col-sm-auto {
+ flex: none;
+ }
+ .col-sm-12 {
+ width: 100%;
+ }
+ .col-sm-11 {
+ width: 91.66666667%;
+ }
+ .col-sm-10 {
+ width: 83.33333333%;
+ }
+ .col-sm-9 {
+ width: 75%;
+ }
+ .col-sm-8 {
+ width: 66.66666667%;
+ }
+ .col-sm-7 {
+ width: 58.33333333%;
+ }
+ .col-sm-6 {
+ width: 50%;
+ }
+ .col-sm-5 {
+ width: 41.66666667%;
+ }
+ .col-sm-4 {
+ width: 33.33333333%;
+ }
+ .col-sm-3 {
+ width: 25%;
+ }
+ .col-sm-2 {
+ width: 16.66666667%;
+ }
+ .col-sm-1 {
+ width: 8.33333333%;
+ }
+ .col-sm-auto {
+ width: auto;
+ }
+ .hide-sm {
+ display: none !important;
+ }
+ .show-sm {
+ display: block !important;
+ }
+ }
+ @media (max-width: $size-xs) {
+ .col-xs-12,
+ .col-xs-11,
+ .col-xs-10,
+ .col-xs-9,
+ .col-xs-8,
+ .col-xs-7,
+ .col-xs-6,
+ .col-xs-5,
+ .col-xs-4,
+ .col-xs-3,
+ .col-xs-2,
+ .col-xs-1,
+ .col-xs-auto {
+ flex: none;
+ }
+ .col-xs-12 {
+ width: 100%;
+ }
+ .col-xs-11 {
+ width: 91.66666667%;
+ }
+ .col-xs-10 {
+ width: 83.33333333%;
+ }
+ .col-xs-9 {
+ width: 75%;
+ }
+ .col-xs-8 {
+ width: 66.66666667%;
+ }
+ .col-xs-7 {
+ width: 58.33333333%;
+ }
+ .col-xs-6 {
+ width: 50%;
+ }
+ .col-xs-5 {
+ width: 41.66666667%;
+ }
+ .col-xs-4 {
+ width: 33.33333333%;
+ }
+ .col-xs-3 {
+ width: 25%;
+ }
+ .col-xs-2 {
+ width: 16.66666667%;
+ }
+ .col-xs-1 {
+ width: 8.33333333%;
+ }
+ .col-xs-auto {
+ width: auto;
+ }
+ .hide-xs {
+ display: none !important;
+ }
+ .show-xs {
+ display: block !important;
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/woocommerce-germanized-shipments/assets/js/admin-shipment-label-backbone.js b/packages/woocommerce-germanized-shipments/assets/js/admin-shipment-label-backbone.js
new file mode 100644
index 000000000..9b720833f
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/assets/js/admin-shipment-label-backbone.js
@@ -0,0 +1,278 @@
+window.germanized = window.germanized || {};
+window.germanized.admin = window.germanized.admin || {};
+
+( function( $, admin ) {
+
+ /**
+ * Core
+ */
+ admin.shipment_label_backbone = {
+
+ params: {},
+
+ init: function () {
+ var self = germanized.admin.shipment_label_backbone;
+ self.params = wc_gzd_admin_shipment_label_backbone_params;
+
+ $( document )
+ .on( 'click', '.germanized-create-label .show-further-services', self.onExpandServices )
+ .on( 'click', '.germanized-create-label .show-fewer-services', self.onHideServices )
+ .on( 'change', '.germanized-create-label input.show-if-trigger', self.onShowIf )
+ .on( 'click', '.germanized-create-label .notice .notice-dismiss', self.onRemoveNotice )
+ .on( 'change', '.germanized-create-label #product_id', self.onChangeProductId );
+
+ $( document.body )
+ .on( 'wc_backbone_modal_loaded', self.backbone.init )
+ .on( 'wc_backbone_modal_response', self.backbone.response );
+ },
+
+ onChangeProductId: function() {
+ var self = germanized.admin.shipment_label_backbone;
+
+ self.showOrHideServices( $( this ).val() );
+ },
+
+ showOrHideServices: function( productId ) {
+ var $services = $( '.show-if-further-services' ).find( 'p.form-field' );
+
+ $services.each( function() {
+ var $service = $( this ),
+ $serviceField = $service.find( ':input' ),
+ supported = $serviceField.data( 'products-supported' ) ? $serviceField.data( 'products-supported' ).split( ',' ) : [],
+ isHidden = false;
+
+ if ( $serviceField.data( 'products-supported' ) ) {
+ isHidden = true;
+
+ if ( $.inArray( productId, supported ) !== -1 ) {
+ isHidden = false;
+ }
+ }
+
+ if ( isHidden ) {
+ $service.hide();
+ } else {
+ $service.show();
+ }
+ } );
+ },
+
+ onRemoveNotice: function() {
+ $( this ).parents( '.notice' ).slideUp( 150, function() {
+ $( this ).remove();
+ });
+ },
+
+ onShowIf: function() {
+ var $wrapper = $( this ).parents( '.germanized-create-label' ),
+ $show = $wrapper.find( $( this ).data( 'show-if' ) ),
+ $checkbox = $( this );
+
+ if ( $show.length > 0 ) {
+ if ( $checkbox.is( ':checked' ) ) {
+ $show.show();
+ } else {
+ $show.hide();
+ }
+
+ $( document.body ).trigger( 'wc_gzd_shipment_label_show_if' );
+ }
+ },
+
+ onExpandServices: function() {
+ var $wrapper = $( this ).parents( '.germanized-create-label' ).find( '.show-if-further-services' ),
+ $trigger = $( this ).parents( '.show-services-trigger' );
+
+ $wrapper.show();
+
+ $trigger.find( '.show-further-services' ).hide();
+ $trigger.find( '.show-fewer-services' ).show();
+
+ return false;
+ },
+
+ onHideServices: function() {
+ var $wrapper = $( this ).parents( '.germanized-create-label' ).find( '.show-if-further-services' ),
+ $trigger = $( this ).parents( '.show-services-trigger' );
+
+ $wrapper.hide();
+
+ $trigger.find( '.show-further-services' ).show();
+ $trigger.find( '.show-fewer-services' ).hide();
+
+ return false;
+ },
+
+ backbone: {
+
+ getShipmentId: function( target ) {
+ return target.replace( /^\D+/g, '' );
+ },
+
+ init: function( e, target ) {
+ if ( target.indexOf( 'wc-gzd-modal-create-shipment-label' ) !== -1 ) {
+ var self = germanized.admin.shipment_label_backbone.backbone,
+ backbone = germanized.admin.shipment_label_backbone,
+ $modal = $( '.germanized-create-label' ).parents( '.wc-backbone-modal-content' ),
+ shipmentId = self.getShipmentId( target ),
+ params = {
+ 'action' : 'woocommerce_gzd_create_shipment_label_form',
+ 'shipment_id': shipmentId,
+ 'security' : backbone.params.create_label_form_nonce
+ };
+
+ self.doAjax( params, $modal, self.onInitForm );
+ }
+ },
+
+ onAjaxSuccess: function( data ) {
+
+ },
+
+ onAjaxError: function( data ) {
+
+ },
+
+ doAjax: function( params, $wrapper, cSuccess, cError ) {
+ var self = germanized.admin.shipment_label_backbone.backbone,
+ backbone = germanized.admin.shipment_label_backbone,
+ $content = $wrapper.find( '.germanized-create-label' );
+
+ cSuccess = cSuccess || self.onAjaxSuccess;
+ cError = cError || self.onAjaxError;
+
+ if ( ! params.hasOwnProperty( 'shipment_id' ) ) {
+ params['shipment_id'] = $( '#wc-gzd-shipment-label-admin-shipment-id' ).val();
+ }
+
+ $wrapper.block({
+ message: null,
+ overlayCSS: {
+ background: '#fff',
+ opacity: 0.6
+ }
+ });
+
+ $wrapper.find( '.notice-wrapper' ).empty();
+
+ $.ajax({
+ type: "POST",
+ url: backbone.params.ajax_url,
+ data: params,
+ success: function( data ) {
+ if ( data.success ) {
+ if ( data.fragments ) {
+ $.each( data.fragments, function ( key, value ) {
+ $( key ).replaceWith( value );
+ });
+ }
+ $wrapper.unblock();
+ cSuccess.apply( $content, [ data ] );
+ } else {
+ $wrapper.unblock();
+ cError.apply( $content, [ data ] );
+
+ $.each( data.messages, function( i, message ) {
+ self.addNotice( message, 'error', $content );
+ });
+
+ // ScrollTo top of modal
+ $content.animate({
+ scrollTop: 0
+ }, 500 );
+ }
+ },
+ error: function( data ) {},
+ dataType: 'json'
+ });
+ },
+
+ onInitForm: function( data ) {
+ var self = germanized.admin.shipment_label_backbone.backbone,
+ shipmentId = data['shipment_id'],
+ $modal = $( '.germanized-create-label' );
+
+ $( document.body ).trigger( 'wc-enhanced-select-init' );
+ $( document.body ).trigger( 'wc-init-datepickers' );
+ $( document.body ).trigger( 'wc_gzd_shipment_label_after_init' );
+
+ $modal.find( 'input.show-if-trigger' ).trigger( 'change' );
+ $modal.find( '#product_id' ).trigger( 'change' );
+
+ $modal.parents( '.wc-backbone-modal' ).on( 'click', '#btn-ok', { 'shipmentId': shipmentId }, self.onSubmit );
+ $modal.parents( '.wc-backbone-modal' ).on( 'touchstart', '#btn-ok', { 'shipmentId': shipmentId }, self.onSubmit );
+ $modal.parents( '.wc-backbone-modal' ).on( 'keydown', { 'shipmentId': shipmentId }, self.onKeyDown );
+ },
+
+ 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;
+ },
+
+ onSubmitSuccess: function( data ) {
+ var self = germanized.admin.shipment_label_backbone.backbone,
+ $modal = $( this ).parents( '.wc-backbone-modal-content' ),
+ shipmentId = data['shipment_id'];
+
+ $modal.find( '.modal-close' ).trigger( 'click' );
+
+ if ( $( 'div#shipment-' + shipmentId ).length > 0 ) {
+ germanized.admin.shipments.initShipment( shipmentId );
+ }
+ },
+
+ onKeyDown: function( e ) {
+ var self = germanized.admin.shipment_label_backbone.backbone,
+ button = e.keyCode || e.which;
+
+ // Enter key
+ if ( 13 === button && ! ( e.target.tagName && ( e.target.tagName.toLowerCase() === 'input' || e.target.tagName.toLowerCase() === 'textarea' ) ) ) {
+ self.onSubmit.apply( $( this ).find( 'button#btn-ok' ), [ e ] );
+ }
+ },
+
+ onSubmit: function( e ) {
+ var self = germanized.admin.shipment_label_backbone.backbone,
+ backbone = germanized.admin.shipment_label_backbone,
+ shipmentId = e.data.shipmentId,
+ $modal = $( this ).parents( '.wc-backbone-modal-content' ),
+ $content = $modal.find( '.germanized-create-label' ),
+ $form = $content.find( 'form' ),
+ params = self.getFormData( $form );
+
+ params['security'] = backbone.params.create_label_nonce;
+ params['shipment_id'] = shipmentId;
+ params['action'] = 'woocommerce_gzd_create_shipment_label';
+
+ self.doAjax( params, $modal, self.onSubmitSuccess );
+
+ e.preventDefault();
+ e.stopPropagation();
+ },
+
+ addNotice: function( message, noticeType, $wrapper ) {
+ $wrapper.find( '.notice-wrapper' ).append( '' );
+ },
+
+ response: function( e, target, data ) {
+ if ( target.indexOf( 'wc-gzd-modal-create-shipment-label' ) !== -1 ) {}
+ }
+ }
+ };
+
+ $( document ).ready( function() {
+ germanized.admin.shipment_label_backbone.init();
+ });
+
+})( jQuery, window.germanized.admin );
diff --git a/packages/woocommerce-germanized-shipments/assets/js/admin-shipment-label-backbone.min.js b/packages/woocommerce-germanized-shipments/assets/js/admin-shipment-label-backbone.min.js
new file mode 100644
index 000000000..837f44574
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/assets/js/admin-shipment-label-backbone.min.js
@@ -0,0 +1 @@
+window.germanized=window.germanized||{},window.germanized.admin=window.germanized.admin||{},function(c){window.germanized.admin.shipment_label_backbone={params:{},init:function(){var e=germanized.admin.shipment_label_backbone;e.params=wc_gzd_admin_shipment_label_backbone_params,c(document).on("click",".germanized-create-label .show-further-services",e.onExpandServices).on("click",".germanized-create-label .show-fewer-services",e.onHideServices).on("change",".germanized-create-label input.show-if-trigger",e.onShowIf).on("click",".germanized-create-label .notice .notice-dismiss",e.onRemoveNotice).on("change",".germanized-create-label #product_id",e.onChangeProductId),c(document.body).on("wc_backbone_modal_loaded",e.backbone.init).on("wc_backbone_modal_response",e.backbone.response)},onChangeProductId:function(){germanized.admin.shipment_label_backbone.showOrHideServices(c(this).val())},showOrHideServices:function(t){c(".show-if-further-services").find("p.form-field").each(function(){var e=c(this),n=e.find(":input"),a=n.data("products-supported")?n.data("products-supported").split(","):[],i=!1;n.data("products-supported")&&(i=!0,-1!==c.inArray(t,a)&&(i=!1)),i?e.hide():e.show()})},onRemoveNotice:function(){c(this).parents(".notice").slideUp(150,function(){c(this).remove()})},onShowIf:function(){var e=c(this).parents(".germanized-create-label").find(c(this).data("show-if")),n=c(this);0'+e+'
')},response:function(e,n,a){n.indexOf("wc-gzd-modal-create-shipment-label")}}},c(document).ready(function(){germanized.admin.shipment_label_backbone.init()})}(jQuery);
\ No newline at end of file
diff --git a/packages/woocommerce-germanized-shipments/assets/js/admin-shipment.js b/packages/woocommerce-germanized-shipments/assets/js/admin-shipment.js
new file mode 100644
index 000000000..4af5a14c7
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/assets/js/admin-shipment.js
@@ -0,0 +1,525 @@
+window.germanized = window.germanized || {};
+window.germanized.admin = window.germanized.admin || {};
+
+( function( $, admin ) {
+
+ $.GermanizedShipment = function( shipmentId ) {
+
+ /*
+ * Variables accessible
+ * in the class
+ */
+ this.vars = {
+ $shipment : false,
+ params : {},
+ id : '',
+ isEditable : true,
+ needsItems : true
+ };
+
+ /*
+ * Can access this.method
+ * inside other methods using
+ * root.method()
+ */
+ this.root = this;
+
+ /*
+ * Constructor
+ */
+ this.construct = function( shipmentId ) {
+ this.vars.id = shipmentId;
+ this.vars.params = germanized.admin.shipments.getParams();
+
+ this.refreshDom();
+
+ $( document.body )
+ .on( 'wc_backbone_modal_loaded', this.backbone.init.bind( this ) )
+ .on( 'wc_backbone_modal_response', this.backbone.response.bind( this ) );
+ };
+
+ this.refreshDom = function() {
+ this.vars.$shipment = $( '#order-shipments-list' ).find( '#shipment-' + this.getId() );
+
+ this.setNeedsItems( this.vars.$shipment.hasClass( 'needs-items' ) );
+ this.setIsEditable( this.vars.$shipment.hasClass( 'is-editable' ) );
+ this.onChangeProvider();
+
+ $( '#shipment-' + this.vars.id + ' #shipment-items-' + this.vars.id ).off();
+ $( '#shipment-' + this.vars.id + ' #shipment-footer-' + this.vars.id ).off();
+ $( '#shipment-' + this.vars.id + ' #shipment-shipping-provider-' + this.vars.id ).off();
+ $( '#shipment-' + this.vars.id + ' #shipment-packaging-' + this.vars.id ).off();
+ $( '#shipment-' + this.vars.id + ' .wc-gzd-shipment-label' ).off();
+
+ $( '#shipment-' + this.vars.id + ' #shipment-shipping-provider-' + this.vars.id ).on( 'change', this.onChangeProvider.bind( this ) );
+ $( '#shipment-' + this.vars.id + ' #shipment-packaging-' + this.vars.id ).on( 'change', this.refreshDimensions.bind( this ) );
+
+ $( '#shipment-' + this.vars.id + ' #shipment-items-' + this.vars.id )
+ .on( 'change', '.item-quantity', this.onChangeQuantity.bind( this ) )
+ .on( 'click', 'a.remove-shipment-item', this.onRemoveItem.bind( this ) )
+ .on( 'click', 'a.add-shipment-item', this.onAddItem.bind( this ) )
+ .on( 'click', 'a.sync-shipment-items', this.onSyncItems.bind( this ) );
+
+ $( '#shipment-' + this.vars.id + ' #shipment-footer-' + this.vars.id )
+ .on( 'click', '.send-return-shipment-notification', this.onSendReturnNotification.bind( this ) )
+ .on( 'click', '.confirm-return-shipment', this.onConfirmReturnRequest.bind( this ) );
+
+ $( '#shipment-' + this.vars.id + ' .wc-gzd-shipment-label' )
+ .on( 'click', '.create-shipment-label:not(.disabled)', this.onCreateLabel.bind( this ) )
+ .on( 'click', '.remove-shipment-label', this.onRemoveLabel.bind( this ) );
+ };
+
+ this.refreshDimensions = function() {
+ var $shipment = this.getShipment(),
+ $select = $shipment.find( '#shipment-packaging-' + this.getId() ),
+ $selected = $select.find( 'option:selected' );
+
+ // No packaging selected - allow manual dimension control
+ if ( '' === $selected.val() ) {
+ $shipment.find( '#shipment-length-' + this.getId() ).removeClass( 'disabled' ).prop( 'disabled', false );
+ $shipment.find( '#shipment-length-' + this.getId() ).val( '' );
+
+ $shipment.find( '#shipment-width-' + this.getId() ).removeClass( 'disabled' ).prop( 'disabled', false );
+ $shipment.find( '#shipment-width-' + this.getId() ).val( '' );
+
+ $shipment.find( '#shipment-height-' + this.getId() ).removeClass( 'disabled' ).prop( 'disabled', false );
+ $shipment.find( '#shipment-height-' + this.getId() ).val( '' );
+ } else {
+ $shipment.find( '#shipment-length-' + this.getId() ).addClass( 'disabled' ).prop( 'disabled', true );
+ $shipment.find( '#shipment-length-' + this.getId() ).val( $selected.data( 'length' ) );
+
+ $shipment.find( '#shipment-width-' + this.getId() ).addClass( 'disabled' ).prop( 'disabled', true );
+ $shipment.find( '#shipment-width-' + this.getId() ).val( $selected.data( 'width' ) );
+
+ $shipment.find( '#shipment-height-' + this.getId() ).addClass( 'disabled' ).prop( 'disabled', true );
+ $shipment.find( '#shipment-height-' + this.getId() ).val( $selected.data( 'height' ) );
+ }
+ };
+
+ this.blockPackaging = function() {
+ this.getShipmentContent().find( '.wc-gzd-shipment-packaging-wrapper' ).block({
+ message: null,
+ overlayCSS: {
+ background: '#fff',
+ opacity: 0.6
+ }
+ });
+ };
+
+ this.unblockPackaging = function() {
+ this.getShipmentContent().find( '.wc-gzd-shipment-packaging-wrapper' ).unblock();
+ };
+
+ this.refreshPackaging = function() {
+ var params = {
+ 'action' : 'woocommerce_gzd_refresh_shipment_packaging',
+ 'shipment_id' : this.getId(),
+ 'security' : germanized.admin.shipments.getParams().refresh_packaging_nonce
+ };
+
+ this.blockPackaging();
+ germanized.admin.shipments.doAjax( params, this.unblockPackaging.bind( this ), this.unblockPackaging.bind( this ) );
+ };
+
+ this.onSendReturnNotification = function() {
+ var params = {
+ 'action' : 'woocommerce_gzd_send_return_shipment_notification_email',
+ 'shipment_id' : this.getId(),
+ 'security' : germanized.admin.shipments.getParams().send_return_notification_nonce
+ };
+
+ this.block();
+ germanized.admin.shipments.doAjax( params, this.unblock.bind( this ), this.unblock.bind( this ) );
+
+ return false;
+ };
+
+ this.onConfirmReturnRequest = function() {
+ var params = {
+ 'action' : 'woocommerce_gzd_confirm_return_request',
+ 'shipment_id' : this.getId(),
+ 'security' : germanized.admin.shipments.getParams().confirm_return_request_nonce
+ };
+
+ this.block();
+ germanized.admin.shipments.doAjax( params, this.unblock.bind( this ), this.unblock.bind( this ) );
+
+ return false;
+ };
+
+ this.onRemoveLabel = function() {
+ var answer = window.confirm( germanized.admin.shipments.getParams().i18n_remove_label_notice );
+
+ if ( answer ) {
+ this.removeLabel();
+ }
+
+ return false;
+ };
+
+ this.removeLabel = function() {
+ var params = {
+ 'action' : 'woocommerce_gzd_remove_shipment_label',
+ 'shipment_id' : this.getId(),
+ 'security' : germanized.admin.shipments.getParams().remove_label_nonce
+ };
+
+ this.block();
+ germanized.admin.shipments.doAjax( params, this.unblock.bind( this ), this.unblock.bind( this ) );
+ };
+
+ this.onCreateLabel = function() {
+ var $shipment = this.getShipment();
+
+ $shipment.WCBackboneModal({
+ template: 'wc-gzd-modal-create-shipment-label-' + this.getId()
+ });
+
+ return false;
+ };
+
+ this.onChangeProvider = function() {
+ var $shipment = this.getShipment(),
+ $select = $shipment.find( '#shipment-shipping-provider-' + this.getId() ),
+ $selected = $select.find( 'option:selected' );
+
+ $shipment.find( '.show-if-provider' ).hide();
+
+ if ( $selected.length > 0 && $selected.data( 'is-manual' ) && 'yes' === $selected.data( 'is-manual' ) ) {
+ $shipment.find( '.show-if-provider-is-manual' ).show();
+ }
+
+ $shipment.find( '.show-if-provider-' + $select.val() ).show();
+ };
+
+ this.getShipment = function() {
+ return this.vars.$shipment;
+ };
+
+ this.getShipmentContent = function() {
+ return this.vars.$shipment.find( '> .shipment-content-wrapper > .shipment-content > .columns > div:not(.shipment-returns-data)' );
+ };
+
+ this.onChangeQuantity = function( e ) {
+ var $quantity = $( e.target ),
+ $item = $quantity.parents( '.shipment-item' ),
+ itemId = $item.data( 'id' ),
+ newQuantity = $quantity.val();
+
+ this.blockItems();
+
+ var params = {
+ 'action' : 'woocommerce_gzd_limit_shipment_item_quantity',
+ 'shipment_id' : this.getId(),
+ 'item_id' : itemId,
+ 'quantity' : newQuantity
+ };
+
+ germanized.admin.shipments.doAjax( params, this.onChangeQuantitySuccess.bind( this ) );
+ };
+
+ this.onChangeQuantitySuccess = function( data ) {
+ var $item = this.getShipment().find( '.shipment-item[data-id="' + data.item_id + '"]' ),
+ currentQty = $item.find( '.item-quantity' ).val(),
+ maxQuantity = data.max_quantity;
+
+ if ( currentQty > maxQuantity ) {
+ $item.find( '.item-quantity' ).val( maxQuantity );
+ } else if ( currentQty <= 0 ) {
+ $item.find( '.item-quantity' ).val( 1 );
+ }
+
+ this.refreshDom();
+ this.unblockItems();
+ };
+
+ this.setWeight = function( weight ) {
+ this.getShipment().find( '#shipment-weight-' + this.getId() ).attr( 'placeholder', weight );
+ };
+
+ this.setLength = function( length ) {
+ this.getShipment().find( '#shipment-length-' + this.getId() ).attr( 'placeholder', length );
+ };
+
+ this.setWidth = function( width ) {
+ this.getShipment().find( '#shipment-width-' + this.getId() ).attr( 'placeholder', width );
+ };
+
+ this.setHeight = function( height ) {
+ this.getShipment().find( '#shipment-height-' + this.getId() ).attr( 'placeholder', height );
+ };
+
+ this.setTotalWeight = function( weight ) {
+
+ };
+
+ this.setIsEditable = function( isEditable ) {
+ var root = this;
+
+ if ( typeof isEditable !== "boolean" ) {
+ isEditable = true;
+ }
+
+ this.vars.isEditable = isEditable === true;
+
+ if ( ! this.vars.isEditable ) {
+ this.getShipment().removeClass( 'is-editable' );
+ this.getShipment().addClass( 'is-locked' );
+
+ // Disable inputs
+ this.getShipmentContent().find( '.remove-shipment-item ' ).hide();
+ this.getShipmentContent().find( '.shipment-item-actions' ).hide();
+ this.getShipmentContent().find( ':input:not([type=hidden])' ).prop( 'disabled', true );
+
+ $.each( this.vars.params.shipment_locked_excluded_fields, function( i, field ) {
+ root.getShipmentContent().find( ':input[name^=shipment_' + field + ']' ).prop( 'disabled', false );
+ });
+
+ } else {
+ this.getShipment().addClass( 'is-editable' );
+ this.getShipment().removeClass( 'is-locked' );
+
+ // Disable inputs
+ this.getShipmentContent().find( '.remove-shipment-item ' ).show();
+ this.getShipmentContent().find( '.shipment-item-actions' ).show();
+ this.getShipmentContent().find( ':input:not(.disabled):not([type=hidden])' ).prop( 'disabled', false );
+ }
+ };
+
+ this.setNeedsItems = function( needsItems ) {
+ if ( typeof needsItems !== "boolean" ) {
+ needsItems = true;
+ }
+
+ this.vars.needsItems = needsItems === true;
+
+ if ( ! this.vars.needsItems ) {
+ this.getShipment().removeClass( 'needs-items' );
+ } else {
+ this.getShipment().addClass( 'needs-items' );
+ }
+ };
+
+ this.onSyncItems = function() {
+ this.syncItems();
+
+ return false;
+ };
+
+ this.syncItems = function() {
+ this.blockItems();
+
+ var params = {
+ 'action' : 'woocommerce_gzd_sync_shipment_items',
+ 'shipment_id': this.getId()
+ };
+
+ germanized.admin.shipments.doAjax( params, this.onSyncItemsSuccess.bind( this ), this.onSyncItemsError.bind( this ) );
+ };
+
+ this.onSyncItemsSuccess = function( data ) {
+ this.unblockItems();
+ };
+
+ this.onSyncItemsError = function( data ) {
+ this.unblockItems();
+ };
+
+ this.onAddItem = function() {
+
+ this.getShipment().WCBackboneModal({
+ template: 'wc-gzd-modal-add-shipment-item-' + this.getId()
+ });
+
+ return false;
+ };
+
+ this.addItem = function( orderItemId, quantity ) {
+ quantity = quantity || 1;
+
+ this.blockItems();
+
+ var params = {
+ 'action' : 'woocommerce_gzd_add_shipment_item',
+ 'shipment_id' : this.getId(),
+ 'original_item_id' : orderItemId,
+ 'quantity' : quantity
+ };
+
+ germanized.admin.shipments.doAjax( params, this.onAddItemSuccess.bind( this ), this.onAddItemError.bind( this ) );
+ };
+
+ this.addReturn = function( items ) {
+ this.block();
+
+ var params = {
+ 'action' : 'woocommerce_gzd_add_shipment_return',
+ 'shipment_id' : this.getId()
+ };
+
+ $.extend( params, items );
+
+ germanized.admin.shipments.doAjax( params, this.onAddReturnSuccess.bind( this ), this.onAddReturnError.bind( this ) );
+ };
+
+ this.onAddReturnSuccess = function( data ) {
+ this.getShipment().find( '.shipment-return-list' ).append( data.new_shipment );
+
+ this.refreshDom();
+ germanized.admin.shipments.initShipments();
+
+ this.unblock();
+ };
+
+ this.onAddReturnError = function( data ) {
+ this.unblock();
+ };
+
+ this.onAddItemError = function( data ) {
+ this.unblockItems();
+ };
+
+ this.onAddItemSuccess = function( data ) {
+ this.getShipmentContent().find( '.shipment-item-list' ).append( data.new_item );
+
+ this.refreshDom();
+ this.unblockItems();
+ };
+
+ this.onRemoveItem = function( e ) {
+ var $delete = $( e.target ),
+ $item = $delete.parents( '.shipment-item' ),
+ itemId = $item.data( 'id' );
+
+ if ( $item.length > 0 ) {
+ this.removeItem( itemId );
+ }
+
+ return false;
+ };
+
+ this.blockItems = function() {
+ this.getShipmentContent().find( '.shipment-items' ).block({
+ message: null,
+ overlayCSS: {
+ background: '#fff',
+ opacity: 0.6
+ }
+ });
+ };
+
+ this.block = function() {
+ this.getShipment().block({
+ message: null,
+ overlayCSS: {
+ background: '#fff',
+ opacity: 0.6
+ }
+ });
+ };
+
+ this.unblockItems = function() {
+ this.getShipmentContent().find( '.shipment-items' ).unblock();
+ };
+
+ this.unblock = function() {
+ this.getShipment().unblock();
+ };
+
+ this.removeItem = function( itemId ) {
+ var $item = this.getShipment().find( '.shipment-item[data-id="' + itemId + '"]' );
+
+ var params = {
+ 'action' : 'woocommerce_gzd_remove_shipment_item',
+ 'shipment_id' : this.getId(),
+ 'item_id' : itemId
+ };
+
+ this.blockItems();
+
+ germanized.admin.shipments.doAjax( params, this.onRemoveItemSuccess.bind( this ) );
+ };
+
+ this.onRemoveItemSuccess = function( data ) {
+ var $item = this.getShipment().find( '.shipment-item[data-id="' + data['item_id'] + '"]' );
+
+ if ( $item.length > 0 ) {
+ $item.slideUp( 150, function() {
+ $( this ).remove();
+ });
+ }
+
+ this.unblockItems();
+ };
+
+ this.getId = function() {
+ return this.vars.id;
+ };
+
+ this.backbone = {
+
+ onAddItemSuccess: function( data ) {
+ $select = $( 'select#wc-gzd-shipment-add-items-select' );
+ $quantity = $( 'input#wc-gzd-shipment-add-items-quantity' );
+
+ $quantity.val( 1 );
+
+ $.each( data.items, function( id, item ) {
+ $select.append( '' + item.name + ' ' );
+ $quantity.data( 'max-quantity-' + id, item.max_quantity );
+ });
+
+ $( '.wc-backbone-modal-content article' ).unblock();
+
+ $( document.body ).on( 'change', 'input#wc-gzd-shipment-add-items-quantity', function() {
+ var item_id = $select.val(),
+ quantity = $( this ).val();
+
+ if ( $quantity.data( 'max-quantity-' + item_id ) ) {
+ var maxQuantity = $quantity.data( 'max-quantity-' + item_id );
+
+ if ( quantity > maxQuantity ) {
+ $quantity.val( maxQuantity );
+ }
+ }
+ });
+ },
+
+ init: function ( e, target ) {
+ var id = this.getId();
+
+ if ( ( 'wc-gzd-modal-add-shipment-item-' + id ) === target ) {
+
+ $( '.wc-backbone-modal-content article' ).block({
+ message: null,
+ overlayCSS: {
+ background: '#fff',
+ opacity: 0.6
+ }
+ });
+
+ germanized.admin.shipments.doAjax( {
+ 'action' : 'woocommerce_gzd_get_available_shipment_items',
+ 'shipment_id': id
+ }, this.backbone.onAddItemSuccess.bind( this ) );
+
+ return false;
+ }
+ },
+
+ response: function ( e, target, data ) {
+ var id = this.getId();
+
+ if ( ( 'wc-gzd-modal-add-shipment-item-' + id ) === target ) {
+ this.addItem( data.item_id, data.item_qty );
+ }
+ }
+ };
+
+ /*
+ * Pass options when class instantiated
+ */
+ this.construct( shipmentId );
+ };
+
+})( jQuery, window.germanized.admin );
diff --git a/packages/woocommerce-germanized-shipments/assets/js/admin-shipment.min.js b/packages/woocommerce-germanized-shipments/assets/js/admin-shipment.min.js
new file mode 100644
index 000000000..5b17f9c69
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/assets/js/admin-shipment.min.js
@@ -0,0 +1 @@
+window.germanized=window.germanized||{},window.germanized.admin=window.germanized.admin||{},function(h){h.GermanizedShipment=function(t){this.vars={$shipment:!1,params:{},id:"",isEditable:!0,needsItems:!0},(this.root=this).construct=function(t){this.vars.id=t,this.vars.params=germanized.admin.shipments.getParams(),this.refreshDom(),h(document.body).on("wc_backbone_modal_loaded",this.backbone.init.bind(this)).on("wc_backbone_modal_response",this.backbone.response.bind(this))},this.refreshDom=function(){this.vars.$shipment=h("#order-shipments-list").find("#shipment-"+this.getId()),this.setNeedsItems(this.vars.$shipment.hasClass("needs-items")),this.setIsEditable(this.vars.$shipment.hasClass("is-editable")),this.onChangeProvider(),h("#shipment-"+this.vars.id+" #shipment-items-"+this.vars.id).off(),h("#shipment-"+this.vars.id+" #shipment-footer-"+this.vars.id).off(),h("#shipment-"+this.vars.id+" #shipment-shipping-provider-"+this.vars.id).off(),h("#shipment-"+this.vars.id+" #shipment-packaging-"+this.vars.id).off(),h("#shipment-"+this.vars.id+" .wc-gzd-shipment-label").off(),h("#shipment-"+this.vars.id+" #shipment-shipping-provider-"+this.vars.id).on("change",this.onChangeProvider.bind(this)),h("#shipment-"+this.vars.id+" #shipment-packaging-"+this.vars.id).on("change",this.refreshDimensions.bind(this)),h("#shipment-"+this.vars.id+" #shipment-items-"+this.vars.id).on("change",".item-quantity",this.onChangeQuantity.bind(this)).on("click","a.remove-shipment-item",this.onRemoveItem.bind(this)).on("click","a.add-shipment-item",this.onAddItem.bind(this)).on("click","a.sync-shipment-items",this.onSyncItems.bind(this)),h("#shipment-"+this.vars.id+" #shipment-footer-"+this.vars.id).on("click",".send-return-shipment-notification",this.onSendReturnNotification.bind(this)).on("click",".confirm-return-shipment",this.onConfirmReturnRequest.bind(this)),h("#shipment-"+this.vars.id+" .wc-gzd-shipment-label").on("click",".create-shipment-label:not(.disabled)",this.onCreateLabel.bind(this)).on("click",".remove-shipment-label",this.onRemoveLabel.bind(this))},this.refreshDimensions=function(){var t=this.getShipment(),i=t.find("#shipment-packaging-"+this.getId()).find("option:selected");""===i.val()?(t.find("#shipment-length-"+this.getId()).removeClass("disabled").prop("disabled",!1),t.find("#shipment-length-"+this.getId()).val(""),t.find("#shipment-width-"+this.getId()).removeClass("disabled").prop("disabled",!1),t.find("#shipment-width-"+this.getId()).val(""),t.find("#shipment-height-"+this.getId()).removeClass("disabled").prop("disabled",!1),t.find("#shipment-height-"+this.getId()).val("")):(t.find("#shipment-length-"+this.getId()).addClass("disabled").prop("disabled",!0),t.find("#shipment-length-"+this.getId()).val(i.data("length")),t.find("#shipment-width-"+this.getId()).addClass("disabled").prop("disabled",!0),t.find("#shipment-width-"+this.getId()).val(i.data("width")),t.find("#shipment-height-"+this.getId()).addClass("disabled").prop("disabled",!0),t.find("#shipment-height-"+this.getId()).val(i.data("height")))},this.blockPackaging=function(){this.getShipmentContent().find(".wc-gzd-shipment-packaging-wrapper").block({message:null,overlayCSS:{background:"#fff",opacity:.6}})},this.unblockPackaging=function(){this.getShipmentContent().find(".wc-gzd-shipment-packaging-wrapper").unblock()},this.refreshPackaging=function(){var t={action:"woocommerce_gzd_refresh_shipment_packaging",shipment_id:this.getId(),security:germanized.admin.shipments.getParams().refresh_packaging_nonce};this.blockPackaging(),germanized.admin.shipments.doAjax(t,this.unblockPackaging.bind(this),this.unblockPackaging.bind(this))},this.onSendReturnNotification=function(){var t={action:"woocommerce_gzd_send_return_shipment_notification_email",shipment_id:this.getId(),security:germanized.admin.shipments.getParams().send_return_notification_nonce};return this.block(),germanized.admin.shipments.doAjax(t,this.unblock.bind(this),this.unblock.bind(this)),!1},this.onConfirmReturnRequest=function(){var t={action:"woocommerce_gzd_confirm_return_request",shipment_id:this.getId(),security:germanized.admin.shipments.getParams().confirm_return_request_nonce};return this.block(),germanized.admin.shipments.doAjax(t,this.unblock.bind(this),this.unblock.bind(this)),!1},this.onRemoveLabel=function(){return window.confirm(germanized.admin.shipments.getParams().i18n_remove_label_notice)&&this.removeLabel(),!1},this.removeLabel=function(){var t={action:"woocommerce_gzd_remove_shipment_label",shipment_id:this.getId(),security:germanized.admin.shipments.getParams().remove_label_nonce};this.block(),germanized.admin.shipments.doAjax(t,this.unblock.bind(this),this.unblock.bind(this))},this.onCreateLabel=function(){return this.getShipment().WCBackboneModal({template:"wc-gzd-modal-create-shipment-label-"+this.getId()}),!1},this.onChangeProvider=function(){var t=this.getShipment(),i=t.find("#shipment-shipping-provider-"+this.getId()),e=i.find("option:selected");t.find(".show-if-provider").hide(),0 .shipment-content-wrapper > .shipment-content > .columns > div:not(.shipment-returns-data)")},this.onChangeQuantity=function(t){var i=h(t.target),e=i.parents(".shipment-item").data("id"),n=i.val();this.blockItems();var s={action:"woocommerce_gzd_limit_shipment_item_quantity",shipment_id:this.getId(),item_id:e,quantity:n};germanized.admin.shipments.doAjax(s,this.onChangeQuantitySuccess.bind(this))},this.onChangeQuantitySuccess=function(t){var i=this.getShipment().find('.shipment-item[data-id="'+t.item_id+'"]'),e=i.find(".item-quantity").val(),n=t.max_quantity;n'+i.name+""),$quantity.data("max-quantity-"+t,i.max_quantity)}),h(".wc-backbone-modal-content article").unblock(),h(document.body).on("change","input#wc-gzd-shipment-add-items-quantity",function(){var t,i=$select.val(),e=h(this).val();!$quantity.data("max-quantity-"+i)||(t=$quantity.data("max-quantity-"+i)) 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..e23d3b485
--- /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=germanized.admin.shipments_table,t=s(this).parents(".bulkactions").find("select[name^=action]").val(),e=s(this).parents("#posts-filter").find("input.shipment_type").val(),a=[];if(s("#posts-filter").find('input[name="shipment[]"]:checked').each(function(){a.push(s(this).val())}),n.params.bulk_actions.hasOwnProperty(t)&&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( '' );
+ },
+
+ 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,
+ $shipment = self.$wrapper.find( '#shipment-' + data['shipment_id'] );
+
+ if ( $shipment.length > 0 ) {
+
+ if ( $shipment.hasClass( 'active' ) ) {
+ $shipment.find( '.shipment-content-wrapper' ).slideUp( 300, function() {
+ $shipment.removeClass( 'active' );
+ $shipment.remove();
+
+ self.initShipments();
+ self.unblock();
+ });
+ } else {
+ $shipment.remove();
+
+ self.initShipments();
+ self.unblock();
+ }
+ } else {
+ 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..5d2f174ff
--- /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 r,a=i.data,s=!1;try{s=JSON.parse('{"'+a.replace(/&/g,'","').replace(/=/g,'":"')+'"}',function(e,n){return""===e?n:decodeURIComponent(n)})}catch(e){s=!1}s&&s.hasOwnProperty("action")&&("woocommerce_save_order_items"!==(r=s.action)&&"woocommerce_remove_order_item"!==r&&"woocommerce_add_order_item"!==r&&"woocommerce_delete_refund"!==r||t.syncItemQuantities())}},syncItemQuantities:function(){var e=germanized.admin.shipments;e.block();var n={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;e.block();var n={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,i={action:"woocommerce_gzd_remove_shipment",shipment_id:e};n.block(),n.doAjax(i,n.onRemoveShipmentSuccess,n.onRemoveShipmentError)},onRemoveShipmentSuccess:function(e){var n=germanized.admin.shipments,i=n.$wrapper.find("#shipment-"+e.shipment_id);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..87fa22a89
--- /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"),o={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(o,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..2c3a4e16c
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipment-content.php
@@ -0,0 +1,254 @@
+
+
+
+
+
+
+
+
+
+
+ get_weight_unit() ); ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $title ) : ?>
+ get_status(), true ); ?>>
+
+
+
+
+ get_available_shipping_methods() ) > 1 ) : ?>
+
+
+
+ get_available_shipping_methods() as $method => $title ) : ?>
+ get_shipping_method(), true ); ?>>
+
+
+
+
+
+
+
+
+ $title ) :
+ $provider_instance = wc_gzd_get_shipping_provider( $provider );
+ ?>
+ get_shipping_provider(), true ); ?>>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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..a825258a1
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipment-item-count.php
@@ -0,0 +1,18 @@
+
+
+
+ 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..8c46294d4
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipment-item.php
@@ -0,0 +1,68 @@
+
+
+
+
+ $column ) : ?>
+
+
+
+
+
+ get_name() ); ?> get_sku() ? '
(' . esc_html( $item->get_sku() ) . ') ' : '' ); ?>
+
+
+
+
+
+
+ get_order_item() ) as $reason ) : ?>
+ get_code(), $item->get_return_reason_code() ); ?>>get_reason(); ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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..a3d4852c7
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipment-list.php
@@ -0,0 +1,32 @@
+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..5e1ff239e
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipment-packaging-select.php
@@ -0,0 +1,34 @@
+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;
+?>
+
+
+ get_id() == $default_packaging_id ) {
+ $default_exists_in_list = true;
+ }
+ ?>
+ get_id(), $shipment->get_packaging_id(), true ); ?>
+ >get_title(); ?>
+
+
+
+ get_id(), $shipment->get_packaging_id(), true ); ?>>get_title(); ?> ()
+
+
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..4eb5eedf5
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipment.php
@@ -0,0 +1,31 @@
+
+
+
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..a3cbab2b7
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/includes/admin/views/html-order-shipments.php
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+ 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..70ddb120d
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/includes/admin/views/html-settings-provider-list.php
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ $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..5711b55f3
--- /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..1c63ed09f
--- /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..05e78672b
--- /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..b36031d95
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/includes/admin/views/label/html-shipment-label.php
@@ -0,0 +1,48 @@
+
+
+
+
get_shipping_provider() ) ); ?> has_label() && $shipment->get_tracking_id() ) ? 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..c8b524863
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/includes/emails/class-wc-gzd-email-customer-guest-return-shipment-request.php
@@ -0,0 +1,212 @@
+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..a785a82e1
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/includes/emails/class-wc-gzd-email-customer-return-shipment-delivered.php
@@ -0,0 +1,232 @@
+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..372feb684
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/includes/emails/class-wc-gzd-email-customer-return-shipment.php
@@ -0,0 +1,265 @@
+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..df29b8192
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/includes/emails/class-wc-gzd-email-customer-shipment.php
@@ -0,0 +1,376 @@
+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}' => '',
+ );
+
+ // 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', 'shipments', 'woocommerce-germanized' );
+ } else {
+ return _x( 'Your {site_title} order #{order_number} has been shipped', '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 );
+ }
+
+ /**
+ * 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 );
+ }
+
+ /**
+ * 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.
+ */
+ 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();
+
+ if ( $order_shipment->needs_shipping() || sizeof( $order_shipment->get_simple_shipments() ) > 1 ) {
+ $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();
+
+ 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,
+ '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,
+ '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,
+ /* translators: %s: list of placeholders */
+ 'description' => sprintf( _x( 'Available placeholders: %s', 'shipments', 'woocommerce-germanized' ), '{site_title}, {order_date}, {order_number}, {shipment_number}, {date_sent}
' ),
+ 'placeholder' => $this->get_default_subject(),
+ 'default' => '',
+ ),
+ 'subject_partial' => array(
+ 'title' => _x( 'Partial shipment subject', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'desc_tip' => true,
+ /* translators: %s: list of placeholders */
+ 'description' => sprintf( _x( 'Available placeholders: %s', 'shipments', 'woocommerce-germanized' ), '{site_title}, {order_date}, {order_number}, {shipment_number}, {date_sent}
' ),
+ 'placeholder' => $this->get_default_subject( true ),
+ 'default' => '',
+ ),
+ 'heading_full' => array(
+ 'title' => _x( 'Full shipment email heading', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'desc_tip' => true,
+ /* translators: %s: list of placeholders */
+ 'description' => sprintf( _x( 'Available placeholders: %s', 'shipments', 'woocommerce-germanized' ), '{site_title}, {order_date}, {order_number}, {shipment_number}, {date_sent}
' ),
+ 'placeholder' => $this->get_default_heading(),
+ 'default' => '',
+ ),
+ 'heading_partial' => array(
+ 'title' => _x( 'Partial shipment email heading', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'desc_tip' => true,
+ /* translators: %s: list of placeholders */
+ 'description' => sprintf( _x( 'Available placeholders: %s', 'shipments', 'woocommerce-germanized' ), '{site_title}, {order_date}, {order_number}, {shipment_number}, {date_sent}
' ),
+ '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..ff6cec8d5
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/includes/emails/class-wc-gzd-email-new-return-shipment-request.php
@@ -0,0 +1,216 @@
+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..0ab7ffee2
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/includes/wc-gzd-label-functions.php
@@ -0,0 +1,147 @@
+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;
+ }
+ }
+
+ 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..39a3e0e6c
--- /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..a774f3b49
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/includes/wc-gzd-shipment-functions.php
@@ -0,0 +1,1323 @@
+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__, func_get_args() );
+ 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' ),
+ );
+
+ /**
+ * 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_numeric( $instance_id ) ) {
+ if ( strpos( $instance_id, ':' ) !== false ) {
+ $expl = explode( ':', $instance_id );
+ $instance_id = ( ( ! empty( $expl ) && sizeof( $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;
+
+ if ( ! $method = WC()->session->get( $cache_key ) ) {
+ $method = WC_Shipping_Zones::get_shipping_method( $instance_id );
+
+ if ( $method ) {
+ WC()->session->set( $cache_key, $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 );
+}
+
+function wc_gzd_get_current_shipping_provider_method() {
+ $chosen_shipping_methods = WC()->session ? WC()->session->get( 'chosen_shipping_methods' ) : array();
+
+ if ( ! empty( $chosen_shipping_methods ) ) {
+ $method = wc_gzd_get_shipping_provider_method( $chosen_shipping_methods[0] );
+
+ return $method;
+ }
+
+ 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( $streetStr ) {
+ $return = array(
+ 'street' => $streetStr,
+ 'number' => '',
+ );
+
+ try {
+ $split = AddressSplitter::splitAddress( $streetStr );
+
+ $return['street'] = $split['streetName'];
+ $return['number'] = $split['houseNumber'];
+ $return['addition'] = isset( $split['additionToAddress2'] ) ? $split['additionToAddress2'] : '';
+
+ } catch( Exception $e ) {}
+
+ 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 ) ) {
+ $slug = array_search( $provider, $providers );
+ } 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;
+ }
+}
+
+/**
+ * @param Order $shipment_order
+ *
+ * @return array
+ */
+function wc_gzd_get_shipment_return_address( $shipment_order ) {
+ $country_state = wc_format_country_state_string( Package::get_setting( 'return_address_country' ) );
+
+ $address = array(
+ 'first_name' => Package::get_setting( 'return_address_first_name' ),
+ 'last_name' => Package::get_setting( 'return_address_last_name' ),
+ 'company' => Package::get_setting( 'return_address_company' ),
+ 'address_1' => Package::get_setting( 'return_address_address_1' ),
+ 'address_2' => Package::get_setting( 'return_address_address_2' ),
+ 'city' => Package::get_setting( 'return_address_city' ),
+ 'country' => $country_state['country'],
+ 'state' => $country_state['state'],
+ 'postcode' => Package::get_setting( 'return_address_postcode' ),
+ );
+
+ $address['email'] = get_option( 'admin_email' );
+
+ return $address;
+}
+
+/**
+ * @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 .= '' . $action['group'] . ' ' . 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__, func_get_args() );
+ 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( $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'] ) ) : '' );
+
+ return $key;
+}
+
+function wc_gzd_customer_can_add_return_shipment( $order_id ) {
+ $can_view_shipments = false;
+
+ if ( isset( $_REQUEST['key'] ) && ! empty( $_REQUEST['key'] ) ) {
+ $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 );
+}
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 '';
+
+ 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 '';
+
+ 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 '';
+ return;
+ }
+
+ if ( ! wc_gzd_order_is_customer_returnable( $order_id ) ) {
+ echo '';
+ 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 . '
';
+ }
+
+ 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..a1179e1dc
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/AddressSplitter.php
@@ -0,0 +1,270 @@
+
+ */
+ $addition2Introducers = '(?:
+ # {{{ 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:
+ (?!' . $addition2Introducers . ')
+ \s*[\pL\pN]+
+ )
+ # Match any further slash- or dash-based house
+ # number extensions:
+ (?:
+ # Do not match "care-of"-like additions as
+ # house numbers:
+ (?!' . $addition2Introducers . ')
+ # 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 ( $result === 0 ) {
+ throw new Exception( sprintf( 'Error occurred while trying to split address \'%s\'', $address ) );
+ } elseif ( $result === false ) {
+ 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 $houseNumber A house number string to split in base and extension
+ *
+ * @return array
+ * @throws Exception
+ */
+ public static function splitHouseNumber( $houseNumber ) {
+ $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, $houseNumber, $matches );
+ if ( $result === 0 ) {
+ throw new Exception( sprintf( 'Error occurred while trying to house number \'%s\'', $houseNumber ) );
+ } elseif ( $result === false ) {
+ throw new RuntimeException( sprintf( 'Error occurred while trying to house number \'%s\'', $houseNumber ) );
+ }
+
+ 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..7fcb8d724
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/Admin/Admin.php
@@ -0,0 +1,899 @@
+
+
+
wp-content/uploads/' . $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 ) . ' '; // WPCS: override ok.
+ 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 );
+ }
+
+ public 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();
+ }
+
+ // phpcs:disable WordPress.Security.NonceVerification.NoNonceVerification -- Nonce verification already handled in WC_Admin_Settings::save()
+ if ( isset( $_POST['packaging'] ) ) {
+ $packaging_post = wc_clean( wp_unslash( $_POST['packaging'] ) );
+ $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 ) ? '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();
+
+ // phpcs:disable WordPress.Security.NonceVerification.NoNonceVerification -- Nonce verification already handled in WC_Admin_Settings::save()
+ if ( isset( $_POST['shipment_return_reason'] ) ) {
+
+ $reasons_post = wc_clean( wp_unslash( $_POST['shipment_return_reason'] ) );
+ $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();
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _x( 'Shipments', 'shipments', 'woocommerce-germanized' ),
+ 'path' => Package::get_path() . '/templates',
+ 'template_path' => $check['germanized']['template_path'],
+ 'outdated_help_url' => $check['germanized']['outdated_help_url'],
+ 'files' => array(),
+ 'has_outdated' => false,
+ );
+
+ return $check;
+ }
+
+ public static function add_table_view( $screen_ids ) {
+ $screen_ids[] = 'woocommerce_page_wc-gzd-shipments';
+ $screen_ids[] = 'woocommerce_page_wc-gzd-return-shipments';
+
+ return $screen_ids;
+ }
+
+ public static function handle_order_bulk_actions( $redirect_to, $action, $ids ) {
+ $ids = apply_filters( 'woocommerce_bulk_action_ids', array_reverse( array_map( 'absint', $ids ) ), $action, 'order' );
+ $changed = 0;
+ $report_action = '';
+
+ if ( 'gzd_create_shipments' === $action ) {
+
+ foreach ( $ids as $id ) {
+ $order = wc_get_order( $id );
+ $report_action = 'gzd_created_shipments';
+
+ if ( $order ) {
+ Automation::create_shipments( $id, false );
+ $changed++;
+ }
+ }
+ }
+
+ if ( $changed ) {
+ $redirect_to = add_query_arg(
+ array(
+ 'post_type' => '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' ) ) ) {
+ 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;
+ $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 = explode( ',', $_REQUEST['ids'] );
+ } elseif ( ! empty( $_REQUEST['shipment'] ) ) {
+ $shipment_ids = array_map( 'intval', $_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_redirect( $sendback );
+ exit();
+
+ } elseif ( ! empty( $_REQUEST['_wp_http_referer'] ) ) {
+ wp_redirect( remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
+ 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' ), $_SERVER['REQUEST_URI'] );
+ ?>
+
+ views(); ?>
+
+
+
+
+
+
+
+
+
+
+
+ output_notice();
+ $_SERVER['REQUEST_URI'] = remove_query_arg( array( 'updated', 'changed', 'deleted', 'trashed', 'untrashed' ), $_SERVER['REQUEST_URI'] );
+ ?>
+
+ views(); ?>
+
+
+
+
+
+
+ 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() ) ) {
+ 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' ) ) ) {
+ 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'] ) ) {
+ 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() );
+ 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() );
+ 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() );
+ 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() );
+ wp_register_script( 'wc-gzd-admin-shipping-providers', Package::get_assets_url() . '/js/admin-shipping-providers' . $suffix . '.js', array( 'jquery' ), Package::get_version() );
+ 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() );
+
+ // Orders.
+ if ( in_array( str_replace( 'edit-', '', $screen_id ), wc_get_order_types( 'order-meta-boxes' ) ) ) {
+
+ 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'] ) ) {
+ 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'] ) ) ) {
+ 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..1790e2d75
--- /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( sizeof( $this->get_ids() ) / $this->get_limit() );
+ }
+
+ abstract public function get_limit();
+
+ public function get_total() {
+ return sizeof( $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..3654eefce
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/Admin/BulkLabel.php
@@ -0,0 +1,194 @@
+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 = '' . _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( _x( 'Labels partially generated. %s', 'shipments', 'woocommerce-germanized' ), $download_button ) . '
';
+ }
+ }
+
+ 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 %s: %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 ) {}
+ }
+
+ $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..8924f5614
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/Admin/MetaBox.php
@@ -0,0 +1,171 @@
+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 ] ) ) {
+ $props['weight'] = wc_clean( wp_unslash( $_POST['shipment_weight'][ $id ] ) );
+ }
+
+ if ( isset( $_POST['shipment_length'][ $id ] ) ) {
+ $props['length'] = wc_clean( wp_unslash( $_POST['shipment_length'][ $id ] ) );
+ }
+
+ if ( isset( $_POST['shipment_width'][ $id ] ) ) {
+ $props['width'] = wc_clean( wp_unslash( $_POST['shipment_width'][ $id ] ) );
+ }
+
+ if ( isset( $_POST['shipment_height'][ $id ] ) ) {
+ $props['height'] = wc_clean( wp_unslash( $_POST['shipment_height'][ $id ] ) );
+ }
+
+ if ( isset( $_POST['shipment_shipping_method'][ $id ] ) ) {
+ $props['shipping_method'] = wc_clean( wp_unslash( $_POST['shipment_shipping_method'][ $id ] ) );
+ }
+
+ if ( isset( $_POST['shipment_tracking_id'][ $id ] ) ) {
+ $props['tracking_id'] = wc_clean( wp_unslash( $_POST['shipment_tracking_id'][ $id ] ) );
+ }
+
+ if ( isset( $_POST['shipment_packaging_id'][ $id ] ) ) {
+ $props['packaging_id'] = wc_clean( wp_unslash( $_POST['shipment_packaging_id'][ $id ] ) );
+ }
+
+ if ( isset( $_POST['shipment_shipping_provider'][ $id ] ) ) {
+ $provider = wc_clean( wp_unslash( $_POST['shipment_shipping_provider'][ $id ] ) );
+ $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';
+
+ // 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() ) ) {
+ $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 ] ) ) {
+ $props['quantity'] = absint( wp_unslash( $_POST['shipment_item'][ $id ]['quantity'][ $item_id ] ) );
+ }
+
+ if ( isset( $_POST['shipment_item'][ $id ]['return_reason_code'][ $item_id ] ) ) {
+ $props['return_reason_code'] = wc_clean( wp_unslash( $_POST['shipment_item'][ $id ]['return_reason_code'][ $item_id ] ) );
+ }
+
+ $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';
+
+ 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;
+
+ 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..ccbb503b5
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/Admin/ProviderSettings.php
@@ -0,0 +1,253 @@
+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' => '' . 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 ? 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 ( $provider->get_id() <= 0 ) {
+ 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() );
+ }
+ }
+
+ $provider->save();
+
+ 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();
+
+ 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..e8f179bbb
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/Admin/ReturnTable.php
@@ -0,0 +1,100 @@
+';
+ $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..a7d957d11
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/Admin/Settings.php
@@ -0,0 +1,582 @@
+ 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' ) . '',
+ '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;
+ }
+
+ protected static function get_address_settings() {
+ $settings = array(
+ array( 'title' => _x( 'Shipper Address', 'shipments', 'woocommerce-germanized' ), 'type' => 'title', 'id' => 'shipments_shipper_address' ),
+
+ array(
+ 'title' => _x( 'First Name', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'id' => 'woocommerce_gzd_shipments_shipper_address_first_name',
+ 'default' => '',
+ ),
+
+ array(
+ 'title' => _x( 'Last Name', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'id' => 'woocommerce_gzd_shipments_shipper_address_last_name',
+ 'default' => '',
+ ),
+
+ array(
+ 'title' => _x( 'Company', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'id' => 'woocommerce_gzd_shipments_shipper_address_company',
+ 'default' => get_bloginfo( 'name' ),
+ ),
+
+ array(
+ 'title' => _x( 'Address 1', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'id' => 'woocommerce_gzd_shipments_shipper_address_address_1',
+ 'default' => get_option( 'woocommerce_store_address' ),
+ ),
+
+ array(
+ 'title' => _x( 'Address 2', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'id' => 'woocommerce_gzd_shipments_shipper_address_address_2',
+ 'default' => get_option( 'woocommerce_store_address_2' ),
+ ),
+
+ array(
+ 'title' => _x( 'City', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'id' => 'woocommerce_gzd_shipments_shipper_address_city',
+ 'default' => get_option( 'woocommerce_store_city' ),
+ ),
+
+ array(
+ 'title' => _x( 'Country / State', 'shipments', 'woocommerce-germanized' ),
+ 'id' => 'woocommerce_gzd_shipments_shipper_address_country',
+ 'default' => get_option( 'woocommerce_default_country' ),
+ 'type' => 'single_select_country',
+ 'desc_tip' => true,
+ ),
+
+ array(
+ 'title' => _x( 'Postcode', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'id' => 'woocommerce_gzd_shipments_shipper_address_postcode',
+ 'default' => get_option( 'woocommerce_store_postcode' ),
+ ),
+
+ array(
+ 'title' => _x( 'Phone', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'id' => 'woocommerce_gzd_shipments_shipper_address_phone',
+ 'default' => '',
+ ),
+
+ array(
+ 'title' => _x( 'Email', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'id' => 'woocommerce_gzd_shipments_shipper_address_email',
+ 'default' => get_option( 'woocommerce_email_from_address' ),
+ ),
+
+ array( 'type' => 'sectionend', 'id' => 'shipments_shipper_address' ),
+
+ array( 'title' => _x( 'Return Address', 'shipments', 'woocommerce-germanized' ), 'type' => 'title', 'id' => 'shipments_return_address' ),
+
+ array(
+ 'title' => _x( 'First Name', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'id' => 'woocommerce_gzd_shipments_return_address_first_name',
+ 'default' => '',
+ 'placeholder' => get_option( 'woocommerce_gzd_shipments_shipper_address_first_name' )
+ ),
+
+ array(
+ 'title' => _x( 'Last Name', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'id' => 'woocommerce_gzd_shipments_return_address_last_name',
+ 'default' => '',
+ 'placeholder' => get_option( 'woocommerce_gzd_shipments_shipper_address_last_name' )
+ ),
+
+ array(
+ 'title' => _x( 'Company', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'id' => 'woocommerce_gzd_shipments_return_address_company',
+ 'default' => '',
+ 'placeholder' => get_option( 'woocommerce_gzd_shipments_shipper_address_company' )
+ ),
+
+ array(
+ 'title' => _x( 'Address 1', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'id' => 'woocommerce_gzd_shipments_return_address_address_1',
+ 'default' => '',
+ 'placeholder' => get_option( 'woocommerce_gzd_shipments_shipper_address_address_1' )
+ ),
+
+ array(
+ 'title' => _x( 'Address 2', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'id' => 'woocommerce_gzd_shipments_return_address_address_2',
+ 'default' => '',
+ 'placeholder' => get_option( 'woocommerce_gzd_shipments_shipper_address_address_2' )
+ ),
+
+ array(
+ 'title' => _x( 'City', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'id' => 'woocommerce_gzd_shipments_return_address_city',
+ 'default' => '',
+ 'placeholder' => get_option( 'woocommerce_gzd_shipments_shipper_address_city' )
+ ),
+
+ array(
+ 'title' => _x( 'Country / State', 'shipments', 'woocommerce-germanized' ),
+ 'id' => 'woocommerce_gzd_shipments_return_address_country',
+ 'default' => '',
+ 'type' => 'single_select_country',
+ 'placeholder' => get_option( 'woocommerce_gzd_shipments_shipper_address_country' ),
+ 'desc_tip' => true,
+ ),
+
+ array(
+ 'title' => _x( 'Postcode', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'id' => 'woocommerce_gzd_shipments_return_address_postcode',
+ 'default' => '',
+ 'placeholder' => get_option( 'woocommerce_gzd_shipments_shipper_address_postcode' )
+ ),
+
+ array(
+ 'title' => _x( 'Phone', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'id' => 'woocommerce_gzd_shipments_shipper_address_phone',
+ 'default' => '',
+ 'placeholder' => get_option( 'woocommerce_gzd_shipments_shipper_address_phone' )
+ ),
+
+ array(
+ 'title' => _x( 'Email', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'text',
+ 'id' => 'woocommerce_gzd_shipments_return_address_email',
+ 'default' => '',
+ 'placeholder' => get_option( 'woocommerce_gzd_shipments_shipper_address_email' )
+ ),
+
+ 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' => '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 get_sanitized_settings( $settings, $data = null ) {
+ if ( is_null( $data ) ) {
+ $data = $_POST; // WPCS: input var okay, CSRF ok.
+ }
+
+ 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' ) ) || ( 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 ) {
+ ob_start();
+ foreach( $settings as $setting ) {
+ $setting = wp_parse_args( $setting, array( 'id' => '', 'type' => 'text' ) );
+
+ 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( '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( 'services_start' === $setting['type'] ) {
+ $hide_default = isset( $setting['hide_default'] ) ? wc_string_to_bool( $setting['hide_default'] ) : false;
+ $missing_div_closes++;
+ ?>
+
+
+
+
+
+
+
+
+
+ 0 ) {
+ echo '
';
+ $missing_div_closes--;
+ }
+
+ $missing_div_closes++;
+ ?>
+
+ 0 ) {
+ echo '
';
+ $missing_div_closes--;
+ }
+
+ $missing_div_closes++;
+ ?>
+
+
+
+ 0 ) {
+ while( $missing_div_closes > 0 ) {
+ $missing_div_closes--;
+ echo '';
+ }
+ }
+
+ $html = ob_get_clean();
+
+ if ( ! $echo ) {
+ return $html;
+ } else {
+ echo $html;
+ }
+ }
+}
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..8db059761
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/Admin/Table.php
@@ -0,0 +1,1161 @@
+ '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 '' . 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; // WPCS: input var ok, CSRF ok.
+ $bulk_action = isset( $_REQUEST['bulk_action'] ) ? wc_clean( wp_unslash( $_REQUEST['bulk_action'] ) ) : ''; // WPCS: input var ok, CSRF ok.
+
+ 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 );
+
+ /**
+ * 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' );
+ $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 ) ) ) {
+ $args['status'] = wc_clean( wp_unslash( $_REQUEST['shipment_status'] ) );
+ }
+
+ if ( isset( $_REQUEST['orderby'] ) ) {
+ if ( 'weight' === $_REQUEST['orderby'] ) {
+ $args['orderby'] = 'weight';
+ } else {
+ $args['orderby'] = wc_clean( wp_unslash( $_REQUEST['orderby'] ) );
+ }
+ }
+
+ if ( isset( $_REQUEST['order'] ) ) {
+ $args['order'] = 'asc' === $_REQUEST['order'] ? 'ASC' : 'DESC';
+ }
+
+ if ( isset( $_REQUEST['parent_id'] ) && ! empty( $_REQUEST['parent_id'] ) ) {
+ $args['parent_id'] = absint( $_REQUEST['parent_id'] );
+ }
+
+ if ( isset( $_REQUEST['order_id'] ) && ! empty( $_REQUEST['order_id'] ) ) {
+ $args['order_id'] = absint( $_REQUEST['order_id'] );
+ }
+
+ if ( isset( $_REQUEST['m'] ) ) {
+ $m = wc_clean( wp_unslash( $_REQUEST['m'] ) );
+ $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'] ) ) {
+ $search = wc_clean( wp_unslash( $_REQUEST['s'] ) );
+
+ if ( ! is_numeric( $search ) ) {
+ $search = '*' . $search . '*';
+ }
+
+ $args['search'] = $search;
+ }
+
+ // Query the user IDs for this page
+ $this->query = new ShipmentQuery( $args );
+ $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 _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;
+ 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'] ) ) ) {
+ $class = 'current';
+ }
+
+ $all_inner_html = sprintf(
+ _nx(
+ 'All (%s) ',
+ 'All (%s) ',
+ $total_shipments, 'shipments', 'woocommerce-germanized'
+ ),
+ 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 ) ) || empty( $num_shipments[ $status ] ) ) {
+ continue;
+ }
+
+ if ( isset( $_REQUEST['shipment_status'] ) && $status === $_REQUEST['shipment_status'] ) {
+ $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 ] ),
+ 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'] ) ) {
+ 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'] ) {
+ $extra_checks = $wpdb->prepare( ' AND shipment_status = %s', wc_clean( wp_unslash( $_GET['shipment_status'] ) ) );
+ }
+
+ $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
+ " );
+
+ $month_count = count( $months );
+
+ if ( ! $month_count || ( 1 == $month_count && 0 == $months[0]->month ) ) {
+ return;
+ }
+
+ $m = isset( $_GET['m'] ) ? (int) $_GET['m'] : 0;
+ ?>
+
+
+ value="0">
+ year ) {
+ continue;
+ }
+
+ $month = zeroise( $arc_row->month, 2 );
+ $year = $arc_row->year;
+
+ printf(
+ "%s \n",
+ selected( $m, $year . $month, false ),
+ esc_attr( $arc_row->year . $month ),
+ /* translators: 1: month name, 2: 4-digit year */
+ sprintf( __( '%1$s %2$d' ), $wp_locale->get_month( $month ), $year )
+ );
+ }
+ ?>
+
+
+
+ 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;
+
+ 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 array(
+ 'date' => array( 'date_created', false ),
+ 'weight' => 'weight',
+ 'order' => 'order_id'
+ );
+ }
+
+ /**
+ * 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( '%s #%s', 'shipment title', 'woocommerce-germanized' ), wc_gzd_get_shipment_label_title( $shipment->get_type() ), $shipment->get_id() );
+
+ if ( $order = $shipment->get_order() ) {
+ echo '' . $title . ' ';
+ } else {
+ echo $title . ' ';
+ }
+
+ echo '';
+
+ if ( $packaging = $shipment->get_packaging() ) {
+ echo '' . sprintf( _x( '%s', 'shipments', 'woocommerce-germanized' ), $packaging->get_description() ) . ' ';
+ }
+
+ $provider = $shipment->get_shipping_provider();
+
+ if ( ! empty( $provider ) ) {
+ echo '' . sprintf( _x( 'via %s', 'shipments', 'woocommerce-germanized' ), 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 '' . $tracking_id . ' ';
+ } else {
+ echo '' . $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 ); // WPCS: XSS ok.
+
+ /**
+ * 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_id() ); ?>
+
+
+
+
+
+ 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 '' . 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_weight(), $shipment->get_weight_unit() );
+ }
+
+ /**
+ * 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 $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() );
+ }
+
+ /**
+ * 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', current_time( 'timestamp', true ) ) && $shipment_timestamp <= current_time( 'timestamp', true ) ) {
+ $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(), current_time( 'timestamp', true ) )
+ );
+ } 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(
+ '%3$s ',
+ 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 '' . $order->get_order_number() . ' ';
+ } else {
+ echo $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..7733e9692
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/Ajax.php
@@ -0,0 +1,1364 @@
+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' ) ) ) {
+ 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() );
+
+ $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 ) : '',
+ 'tr#shipment-' . $shipment_id . ' td.actions .wc-gzd-shipment-action-button-generate-label' => self::label_download_button_html( $label ),
+ ),
+ );
+ } 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( $_POST['provider'] ) );
+ $enable = wc_clean( $_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( $_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( $_POST['bulk_action'] ) : '';
+ $type = isset( $_POST['type'] ) ? wc_clean( $_POST['type'] ) : 'simple';
+
+ 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;
+ }
+
+ 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 );
+ }
+
+ if ( $shipment->delete( true ) ) {
+ $order_shipment->remove_shipment( $shipment_id );
+
+ $response['shipment_id'] = $shipment_id;
+ $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) $_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;
+ }
+
+ 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( $_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();
+
+ $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 ),
+ );
+
+ 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 && $item_quantity === 0 ) {
+ $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..a9ada6cbd
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/Api.php
@@ -0,0 +1,329 @@
+get_data();
+ $response_order_data['shipments'] = array();
+ $context = 'view';
+
+ if ( $order ) {
+ $order_shipment = wc_gzd_get_shipment_order( $order );
+ $shipments = $order_shipment->get_shipments();
+
+ if ( ! empty( $shipments ) ) {
+
+ foreach( $shipments as $shipment ) {
+
+ $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 ),
+ 'quantity' => $item->get_quantity( $context ),
+ );
+ }
+
+ $shipment_data = array(
+ 'id' => $shipment->get_id(),
+ '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(), $request['dp'] ),
+ 'weight' => $shipment->get_weight( $context ),
+ 'status' => $shipment->get_status(),
+ 'tracking_id' => $shipment->get_tracking_id(),
+ 'tracking_url' => $shipment->get_tracking_url(),
+ 'shipping_provider' => $shipment->get_shipping_provider(),
+ 'dimensions' => array(
+ 'length' => $shipment->get_length( $context ),
+ 'width' => $shipment->get_width( $context ),
+ 'height' => $shipment->get_height( $context ),
+ ),
+ 'address' => $shipment->get_address( $context ),
+ 'items' => $item_data,
+ );
+
+ $response_order_data['shipments'][] = $shipment_data;
+ }
+ }
+ }
+
+ $response->set_data( $response_order_data );
+
+ return $response;
+ }
+
+ public static function order_shipments_schema( $schema ) {
+ $weight_unit = get_option( 'woocommerce_weight_unit' );
+ $dimension_unit = get_option( 'woocommerce_dimension_unit' );
+
+ $schema['shipments'] = array(
+ 'description' => _x( 'List of shipments.', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'array',
+ 'context' => array( 'view', 'edit' ),
+ 'readonly' => true,
+ 'items' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'id' => array(
+ 'description' => _x( 'Shipment ID.', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'integer',
+ '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(),
+ 'readonly' => true,
+ ),
+ 'tracking_id' => array(
+ 'description' => _x( 'Shipment tracking id.', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'string',
+ 'context' => array( 'view', 'edit' ),
+ 'readonly' => true,
+ ),
+ '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' ),
+ 'readonly' => true,
+ ),
+ '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' ),
+ 'readonly' => true,
+ ),
+ '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' ),
+ 'readonly' => true,
+ ),
+ 'weight' => array(
+ /* translators: %s: weight unit */
+ 'description' => sprintf( _x( 'Shipment weight (%s).', 'shipments', 'woocommerce-germanized' ), $weight_unit ),
+ 'type' => 'string',
+ 'context' => array( 'view', 'edit' ),
+ 'readonly' => true,
+ ),
+ 'dimensions' => array(
+ 'description' => _x( 'Shipment dimensions.', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'object',
+ 'context' => array( 'view', 'edit' ),
+ 'readonly' => true,
+ 'properties' => array(
+ 'length' => array(
+ /* translators: %s: dimension unit */
+ 'description' => sprintf( _x( 'Shipment length (%s).', 'shipments', 'woocommerce-germanized' ), $dimension_unit ),
+ 'type' => 'string',
+ 'context' => array( 'view', 'edit' ),
+ 'readonly' => true,
+ ),
+ 'width' => array(
+ /* translators: %s: dimension unit */
+ 'description' => sprintf( _x( 'Shipment width (%s).', 'shipments', 'woocommerce-germanized' ), $dimension_unit ),
+ 'type' => 'string',
+ 'context' => array( 'view', 'edit' ),
+ 'readonly' => true,
+ ),
+ 'height' => array(
+ /* translators: %s: dimension unit */
+ 'description' => sprintf( _x( 'Shipment height (%s).', 'shipments', 'woocommerce-germanized' ), $dimension_unit ),
+ 'type' => 'string',
+ 'context' => array( 'view', 'edit' ),
+ 'readonly' => true,
+ ),
+ ),
+ ),
+ 'address' => array(
+ 'description' => _x( 'Shipping address.', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'object',
+ 'context' => array( 'view', 'edit' ),
+ 'readonly' => true,
+ 'properties' => array(
+ 'first_name' => array(
+ 'description' => _x( 'First name.', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'string',
+ 'context' => array( 'view', 'edit' ),
+ 'readonly' => true,
+ ),
+ 'last_name' => array(
+ 'description' => _x( 'Last name.', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'string',
+ 'context' => array( 'view', 'edit' ),
+ 'readonly' => true,
+ ),
+ 'company' => array(
+ 'description' => _x( 'Company name.', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'string',
+ 'context' => array( 'view', 'edit' ),
+ 'readonly' => true,
+ ),
+ 'address_1' => array(
+ 'description' => _x( 'Address line 1', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'string',
+ 'context' => array( 'view', 'edit' ),
+ 'readonly' => true,
+ ),
+ 'address_2' => array(
+ 'description' => _x( 'Address line 2', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'string',
+ 'context' => array( 'view', 'edit' ),
+ 'readonly' => true,
+ ),
+ 'city' => array(
+ 'description' => _x( 'City name.', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'string',
+ 'context' => array( 'view', 'edit' ),
+ 'readonly' => true,
+ ),
+ 'state' => array(
+ 'description' => _x( 'ISO code or name of the state, province or district.', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'string',
+ 'context' => array( 'view', 'edit' ),
+ 'readonly' => true,
+ ),
+ 'postcode' => array(
+ 'description' => _x( 'Postal code.', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'string',
+ 'context' => array( 'view', 'edit' ),
+ 'readonly' => true,
+ ),
+ 'country' => array(
+ 'description' => _x( 'Country code in ISO 3166-1 alpha-2 format.', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'string',
+ 'context' => array( 'view', 'edit' ),
+ 'readonly' => true,
+ ),
+ ),
+ ),
+ 'items' => array(
+ 'description' => _x( 'Shipment items.', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'array',
+ 'context' => array( 'view', 'edit' ),
+ 'readonly' => true,
+ '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' ),
+ 'readonly' => true,
+ ),
+ 'order_item_id' => array(
+ 'description' => _x( 'Order Item ID.', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'integer',
+ 'context' => array( 'view', 'edit' ),
+ 'readonly' => true,
+ ),
+ 'product_id' => array(
+ 'description' => _x( 'Product ID.', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'mixed',
+ 'context' => array( 'view', 'edit' ),
+ 'readonly' => true,
+ ),
+ 'quantity' => array(
+ 'description' => _x( 'Quantity.', 'shipments', 'woocommerce-germanized' ),
+ 'type' => 'integer',
+ 'context' => array( 'view', 'edit' ),
+ 'readonly' => true,
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ );
+
+ return $schema;
+ }
+
+ public static function register_controllers( $controller ) {
+ $controller['wc/v3']['shipments'] = 'Vendidero\Germanized\Shipments\Rest\Shipments.php';
+
+ 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..37d556412
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/Automation.php
@@ -0,0 +1,185 @@
+get_simple_shipments() as $shipment ) {
+
+ if ( ! $shipment->has_status( array( 'shipped', 'delivered' ) ) ) {
+ $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 : 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_id, $enable_auto_filter = true ) {
+ $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.
+ *
+ * @since 3.1.0
+ * @package Vendidero/Germanized/Shipments
+ */
+ if ( $enable_auto_filter && ! apply_filters( 'woocommerce_gzd_auto_create_shipments_for_order', true, $order_id ) ) {
+ return;
+ }
+
+ if ( $order_shipment = wc_gzd_get_shipment_order( $order_id ) ) {
+ if ( ! apply_filters( 'woocommerce_gzd_auto_create_custom_shipments_for_order', false, $order_id ) ) {
+ $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_id, $shipment_status );
+ }
+ }
+
+ public static function maybe_create_shipments( $order_id ) {
+
+ // 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 );
+ }
+ }
+}
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..6f014f162
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/DataStores/Label.php
@@ -0,0 +1,556 @@
+set_date_created( current_time( 'timestamp', true ) );
+
+ $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' => 0 < $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\DHL\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 ) ) {
+ 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();
+ }
+
+ // 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..e618cdefc
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/DataStores/Packaging.php
@@ -0,0 +1,628 @@
+set_date_created( current_time( 'timestamp', true ) );
+
+ $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' => 0 < $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 ) ) {
+ 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();
+ }
+
+ // 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 );
+
+ wp_cache_set( 'packaging-list', $results, 'packaging' );
+ }
+ } else {
+ $results = $wpdb->get_results( $query );
+ }
+
+ foreach ( $results as $key => $packaging ) {
+ $results[ $key ] = wc_gzd_get_packaging( $packaging );
+ }
+
+ return $results;
+ }
+
+ /**
+ * @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();
+
+ // Get from cache if available.
+ $results = wp_cache_get( 'available-packaging-' . $shipment->get_id(), 'shipments' );
+
+ if ( false === $results && sizeof( $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 ) {
+ $box = new PackagingBox( $packaging );
+ $org_size = sizeof( $items_to_pack );
+
+ $packer = new VolumePacker( $box, $items );
+ $packed = $packer->pack();
+
+ if ( sizeof( $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 );
+ $results = $wpdb->get_results( $query );
+
+ 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 ( sizeof( $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];
+ }
+
+ 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..11735ffbc
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/DataStores/Shipment.php
@@ -0,0 +1,712 @@
+set_date_created( current_time( 'timestamp', true ) );
+ $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 ) ) {
+ $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 ) ) {
+
+ 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' => 0 < $data->shipment_date_created_gmt ? wc_string_to_timestamp( $data->shipment_date_created_gmt ) : null,
+ 'date_sent' => 0 < $data->shipment_date_sent_gmt ? wc_string_to_timestamp( $data->shipment_date_sent_gmt ) : null,
+ 'est_delivery_date' => 0 < $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' ) );
+ }
+ }
+
+ /**
+ * 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 ) ) {
+ 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' ) ) && ! $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();
+ }
+
+ // 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 ) );
+ }
+}
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..249af817e
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/DataStores/ShipmentItem.php
@@ -0,0 +1,350 @@
+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 ) ) {
+ 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;
+
+ switch ( $prop ) {}
+
+ $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..081b54228
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/DataStores/ShippingProvider.php
@@ -0,0 +1,443 @@
+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() ) );
+
+ if ( $provider_name_check ) {
+ $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() ) );
+ $suffix++;
+ } while ( $provider_name_check );
+ $slug = $alt_provider_name;
+ }
+
+ return $slug;
+ }
+
+ /**
+ * 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' ) );
+ }
+ }
+
+ /**
+ * 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 ) ) {
+ 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..ea38422e2
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/Emails.php
@@ -0,0 +1,201 @@
+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' ) ) ) {
+ 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..04adf6a99
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/FormHandler.php
@@ -0,0 +1,280 @@
+ $email,
+ 'post__in' => array( $order_id ),
+ '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(
+ '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'] ) ? $_REQUEST['add-return-shipment-nonce'] : '';
+
+ 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( $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..a99640941
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/Install.php
@@ -0,0 +1,291 @@
+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;
+
+ $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'] ) ) {
+ @mkdir( $dir['basedir'] );
+ }
+
+ if ( ! file_exists( trailingslashit( $dir['basedir'] ) . '.htaccess' ) ) {
+ @file_put_contents( trailingslashit( $dir['basedir'] ) . '.htaccess', 'deny from all' );
+ }
+
+ if ( ! file_exists( trailingslashit( $dir['basedir'] ) . 'index.php' ) ) {
+ @touch( trailingslashit( $dir['basedir'] ) . 'index.php' );
+ }
+ }
+
+ private static function get_schema() {
+ global $wpdb;
+
+ $collate = '';
+
+ if ( $wpdb->has_cap( 'collation' ) ) {
+ $collate = $wpdb->get_charset_collate();
+ }
+
+ $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 default NULL,
+ shipment_date_sent_gmt datetime default NULL,
+ shipment_est_delivery_date datetime default NULL,
+ shipment_est_delivery_date_gmt datetime default NULL,
+ 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(200) NOT NULL DEFAULT '',
+ PRIMARY KEY (shipping_provider_id)
+) $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..adc982953
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/Interfaces/ShipmentLabel.php
@@ -0,0 +1,95 @@
+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'] );
+ }
+
+ 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() ) {
+ 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..d2fff1c8c
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/Labels/DownloadHandler.php
@@ -0,0 +1,127 @@
+ 'no',
+ 'print' => 'no',
+ ) );
+
+ $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( $_REQUEST['_wpnonce'], 'download-shipment-label' ) ) {
+ $shipment_id = absint( $_GET['shipment_id'] );
+ $has_permission = current_user_can( 'edit_shop_orders' );
+
+ $args = self::parse_args( array(
+ 'force' => wc_string_to_bool( isset( $_GET['force'] ) ? wc_clean( $_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 Generic.PHP.NoSilencedErrors.Discouraged
+ }
+ } else {
+ @ob_end_clean(); // phpcs:ignore Generic.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 Generic.PHP.NoSilencedErrors.Discouraged
+
+ if ( ! $file_size ) {
+ return;
+ }
+
+ header( 'Content-Length: ' . $file_size );
+
+ @readfile( $file_path );
+ 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..eb61fe214
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/Labels/Factory.php
@@ -0,0 +1,84 @@
+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;
+ }
+
+ $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__, func_get_args() );
+ 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..d51a0fcde
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/Labels/Label.php
@@ -0,0 +1,604 @@
+ 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_{$this->get_shipping_provider()}_{$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;
+ }
+
+ 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;
+ }
+
+ public function get_length( $context = 'view' ) {
+ return $this->get_prop( 'length', $context );
+ }
+
+ public function get_width( $context = 'view' ) {
+ return $this->get_prop( 'width', $context );
+ }
+
+ 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 ) );
+ }
+
+ 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() ) );
+ }
+
+ 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 sizeof( $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 ) && in_array( $service, $available_services ) ) {
+ $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 ) ) {
+ $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() );
+ }
+
+ 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 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 );
+
+ add_filter( 'wp_unique_filename', function( $new_filename ) use ( $filename ) {
+ return $filename;
+ }, 99 );
+
+ $tmp = wp_upload_bits( $this->get_filename( $file_type ),null, $stream );
+
+ remove_filter( 'wp_unique_filename', function(){}, 99 );
+ 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 = [
+ 'name' => $this->get_filename( $file_type ),
+ 'type' => 'application/pdf',
+ 'tmp_name' => $temp_file,
+ 'error' => 0,
+ 'size' => filesize( $temp_file ),
+ ];
+
+ $overrides = [
+ '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;
+ }
+
+ /**
+ * 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;
+ }
+}
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..46a815c44
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/Labels/Query.php
@@ -0,0 +1,489 @@
+ 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 );
+ } else {
+ $this->results = $wpdb->get_col( $this->request );
+ }
+
+ if ( isset( $qv['count_total'] ) && $qv['count_total'] ) {
+ $found_labels_query = 'SELECT FOUND_ROWS()';
+ $this->total_labels = (int) $wpdb->get_var( $found_labels_query );
+ }
+ }
+
+ 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'] );
+ }
+
+ // Shipping provider
+ if ( isset( $this->args['shipping_provider'] ) ) {
+ $this->query_where .= $wpdb->prepare( " AND label_shipping_provider IN ('%s')", $this->args['shipping_provider'] );
+ }
+
+ // Shipping provider
+ if ( isset( $this->args['product_id'] ) ) {
+ $this->query_where .= $wpdb->prepare( " AND label_product_id IN ('%s')", $this->args['product_id'] );
+ }
+
+ // 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 );
+ } else {
+ $searches[] = $wpdb->prepare( "$col LIKE %s", $like );
+ }
+ }
+
+ 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' ) ) ) {
+ $_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..40ae4315f
--- /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() );
+ }
+
+ 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..b5d58a2b1
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/Order.php
@@ -0,0 +1,910 @@
+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 get_shipping_status() {
+ $status = 'not-shipped';
+ $shipments = $this->get_simple_shipments();
+
+ if ( ! empty( $shipments ) ) {
+ foreach( $shipments as $shipment ) {
+
+ if ( $shipment->has_status( wc_gzd_get_shipment_sent_statuses() ) ) {
+ $status = 'partially-shipped';
+ break;
+ }
+ }
+ }
+
+ if ( ! $this->needs_shipping( array( 'sent_only' => true ) ) ) {
+ $status = 'shipped';
+ }
+
+ return $status;
+ }
+
+ public function has_shipped_shipments() {
+ $shipments = $this->get_simple_shipments();
+
+ foreach( $shipments as $shipment ) {
+
+ if ( $shipment->has_status( wc_gzd_get_shipment_sent_statuses() ) ) {
+ 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->has_status( wc_gzd_get_shipment_sent_statuses() ) ) {
+ $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();
+ }
+ }
+
+ 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 = $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() {
+ $simple = array();
+
+ foreach( $this->get_shipments() as $shipment ) {
+ if ( 'simple' === $shipment->get_type() ) {
+ $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_simple_shipments() as $shipment ) {
+
+ if ( $args['sent_only'] && ! $shipment->has_status( wc_gzd_get_shipment_sent_statuses() ) ) {
+ 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() ) ) {
+ $quantity_left -= $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->has_status( wc_gzd_get_shipment_sent_statuses() ) ) {
+ continue;
+ }
+
+ if ( $item = $shipment->get_item_by_order_item_id( $order_item_id ) ) {
+ $quantity += $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 -= $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 );
+ }
+
+ 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 ) {}
+ }
+ }
+
+ 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->has_status( wc_gzd_get_shipment_sent_statuses() ) ) {
+ 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 = $items[ $item->get_order_item_id() ]->get_quantity() + $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 = $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 = $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 += $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 ) ) {
+ $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..92bfdefea
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/PDFMerger.php
@@ -0,0 +1,143 @@
+_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 = [], $width = 210 ) {
+ if ( file_exists( $filename ) ) {
+ $pageCount = $this->_pdf->setSourceFile( $filename );
+
+ for ( $i = 1; $i <= $pageCount; $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 $pageNumber
+ *
+ * @throws PdfReaderException
+ */
+ private function _addPage( $pageNumber, $width = 210 ) {
+ $pageId = $this->_pdf->importPage( $pageNumber );
+ $size = $this->_pdf->getTemplateSize( $pageId );
+
+ $orientation = isset( $size['orientation'] ) ? $size['orientation'] : '';
+
+ $this->_pdf->addPage( $orientation, $size );
+
+ if ( ! isset( $size['width'] ) || empty( $size['width'] ) ) {
+ $this->_pdf->useImportedPage( $pageId, 0, 0, $width, null, true );
+ } else {
+ $this->_pdf->useImportedPage( $pageId );
+ }
+ }
+
+
+ /**
+ * Check if a specific page should be merged.
+ * If pages are empty, all pages will be merged
+ *
+ * @return bool
+ */
+ private function _isPageInRange( $pageNumber, $pages = [] ) {
+ if ( empty( $pages ) ) {
+ return true;
+ }
+
+ foreach ( $pages as $range ) {
+ if ( in_array( $pageNumber, $this->_getRange( $range ) ) ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Get range by given value
+ *
+ * @param mixed $value
+ *
+ * @return array
+ */
+ private function _getRange( $value = null ) {
+ $value = preg_replace( '/[^0-9\-.]/is', '', $value );
+
+ if ( $value == '' ) {
+ return false;
+ }
+
+ $value = explode( '-', $value );
+ if ( count( $value ) == 1 ) {
+ 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..bd9723932
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/PDFSplitter.php
@@ -0,0 +1,185 @@
+_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 ) {
+
+ } catch( Exception $e ) {}
+ }
+
+ 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 = [] ) {
+ if (file_exists($filename))
+ {
+ $pageCount = $this->_pdf->setSourceFile($filename);
+ for ($i = 1; $i <= $pageCount; $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 $pageNumber
+ * @throws PdfReaderException
+ */
+ private function _addPage($pageNumber)
+ {
+ $pageId = $this->_pdf->importPage($pageNumber);
+ $this->_pdf->addPage();
+ $this->_pdf->useImportedPage($pageId);
+ }
+
+
+ /**
+ * Check if a specific page should be merged.
+ * If pages are empty, all pages will be merged
+ *
+ * @return bool
+ */
+ private function _isPageInRange($pageNumber, $pages = [])
+ {
+ if (empty($pages)) {
+ return true;
+ }
+
+ foreach ($pages as $range) {
+ if (in_array($pageNumber, $this->_getRange($range))) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Get range by given value
+ *
+ * @param mixed $value
+ * @return array
+ */
+ private function _getRange($value = null)
+ {
+ $value = preg_replace('/[^0-9\-.]/is', '', $value);
+
+ if ($value == '') {
+ return false;
+ }
+
+ $value = explode('-', $value);
+ if (count($value) == 1) {
+ 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..c3122f31b
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/Package.php
@@ -0,0 +1,548 @@
+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', '>=' );
+ }
+
+ 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_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 ) );
+ }
+
+ 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();
+
+ 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';
+
+ 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'];
+ }
+}
diff --git a/packages/woocommerce-germanized-shipments/src/Packaging.php b/packages/woocommerce-germanized-shipments/src/Packaging.php
new file mode 100644
index 000000000..ce8235f89
--- /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/PackagingFactory.php b/packages/woocommerce-germanized-shipments/src/PackagingFactory.php
new file mode 100644
index 000000000..b6f0ccaa2
--- /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..f87652519
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/Packing/Helper.php
@@ -0,0 +1,26 @@
+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..530453ac5
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/Packing/OrderItem.php
@@ -0,0 +1,116 @@
+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..4ed184a7a
--- /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) wc_get_dimension( $width, 'mm', wc_gzd_get_packaging_dimension_unit() ),
+ 'length' => (int) wc_get_dimension( $length, 'mm', wc_gzd_get_packaging_dimension_unit() ),
+ 'depth' => (int) 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) 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) 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..2a7856f44
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/Packing/ShipmentItem.php
@@ -0,0 +1,110 @@
+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) wc_get_dimension( $width, 'mm', $dimension_unit ),
+ 'length' => (int) wc_get_dimension( $length, 'mm', $dimension_unit ),
+ 'depth' => (int) wc_get_dimension( $depth, 'mm', $dimension_unit )
+ );
+
+ $weight = empty( $this->item->get_weight() ) ? 0 : wc_format_decimal( $this->item->get_weight() );
+ $this->weight = (int) 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/ReturnReason.php b/packages/woocommerce-germanized-shipments/src/ReturnReason.php
new file mode 100644
index 000000000..aa42e19c2
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/ReturnReason.php
@@ -0,0 +1,43 @@
+ '',
+ '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..b117d45e8
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/ReturnShipment.php
@@ -0,0 +1,631 @@
+ 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;
+ }
+
+ /**
+ * 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 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'];
+ }
+
+ /**
+ * 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 );
+ }
+
+ 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 ) : '';
+ }
+
+ /**
+ * 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' );
+
+ $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' => array_merge( $order->get_address( 'shipping' ), array( 'email' => $order->get_billing_email(), 'phone' => $order->get_billing_phone() ) ),
+ '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;
+ }
+ }
+
+ $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..5d4483bad
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/Shipment.php
@@ -0,0 +1,2371 @@
+ 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_";
+ }
+
+ /**
+ * 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' );
+ }
+
+ 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 ) {
+ 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 ( 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++ ) {
+ $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;
+ }
+
+ /**
+ * 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() ) );
+ }
+
+ /**
+ * 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 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() {
+ $instruction = '';
+
+ if ( $provider = $this->get_shipping_provider_instance() ) {
+ // $instruction = sprintf( _x( 'Your shipment is being processed by %s. If you want to track the shipment, please use the following tracking number: %s. 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' ), wc_gzd_get_shipping_provider_title( $this->get_shipping_provider() ), $this->get_tracking_id() );
+ $instruction = $provider->get_tracking_desc( $this );
+ }
+
+ /**
+ * 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();
+
+ 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 );
+ }
+
+ /**
+ * 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 ) : '';
+ }
+
+ /**
+ * 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() {
+ return array(
+ 'length' => $this->get_length(),
+ 'width' => $this->get_width(),
+ 'height' => $this->get_height(),
+ );
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * 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' ) ) {
+ $sent_stati = wc_gzd_get_shipment_sent_statuses();
+
+ if ( $this->has_status( $sent_stati ) ) {
+
+ // If payment complete status is reached, set paid now.
+ $this->set_date_sent( current_time( 'timestamp', true ) );
+ }
+ }
+ }
+
+ /**
+ * 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 ( $packaging_id == $packaging->get_id() ) {
+ $exists = true;
+ break;
+ }
+ }
+
+ if ( ! $exists ) {
+ $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 {
+ // Reset
+ $this->set_props( array(
+ 'width' => '',
+ 'length' => '',
+ 'height' => '',
+ 'packaging_weight' => ''
+ ) );
+ }
+
+ 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;
+ }
+
+ /**
+ * 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 ) {
+ $this->packaging = wc_gzd_get_packaging( $this->get_packaging_id() );
+ }
+
+ 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->has_status( array( 'delivered', '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..5c89d8a76
--- /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__, func_get_args() );
+ 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..b402ca9a6
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/ShipmentItem.php
@@ -0,0 +1,516 @@
+ 0,
+ 'order_item_id' => 0,
+ 'parent_id' => 0,
+ 'quantity' => 1,
+ 'product_id' => 0,
+ 'weight' => '',
+ 'width' => '',
+ 'length' => '',
+ 'height' => '',
+ 'sku' => '',
+ 'name' => '',
+ 'total' => 0,
+ 'subtotal' => 0,
+ );
+
+ /**
+ * 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' ) {
+
+ if ( 'view' === $context && ( $item = $this->get_order_item() ) ) {
+ return $item->get_name();
+ }
+
+ return $this->get_prop( 'name', $context );
+ }
+
+ /**
+ * 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() );
+ }
+
+ $product = $this->get_product();
+ $tax_total = is_callable( array( $item, 'get_total_tax' ) ) ? $item->get_total_tax() : 0;;
+ $total = is_callable( array( $item, 'get_total' ) ) ? $item->get_total() : 0;
+ $subtotal = is_callable( array( $item, 'get_subtotal' ) ) ? $item->get_subtotal() : 0;
+ $tax_subtotal = is_callable( array( $item, 'get_subtotal_tax' ) ) ? $item->get_subtotal_tax() : 0;
+
+ $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() ) : '',
+ ) );
+ }
+
+ $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() {
+ return array(
+ 'length' => $this->get_length(),
+ 'width' => $this->get_width(),
+ 'height' => $this->get_height(),
+ );
+ }
+
+ public function set_quantity( $quantity ) {
+ $this->set_prop( 'quantity', absint( $quantity ) );
+ }
+
+ public function set_name( $name ) {
+ $this->set_prop( 'name', $name );
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | 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..107de9f95
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/ShipmentQuery.php
@@ -0,0 +1,532 @@
+ 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;
+ }
+
+ /**
+ * 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 );
+ } else {
+ $this->results = $wpdb->get_col( $this->request );
+ }
+
+ if ( isset( $qv['count_total'] ) && $qv['count_total'] ) {
+ $found_shipments_query = 'SELECT FOUND_ROWS()';
+ $this->total_shipments = (int) $wpdb->get_var( $found_shipments_query );
+ }
+ }
+
+ 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() ) ) {
+ $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'] );
+ }
+
+ // 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'] );
+ }
+
+ // 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' );
+ } 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 );
+ } else {
+ $searches[] = $wpdb->prepare( "$col LIKE %s", $like );
+ }
+ }
+
+ 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' ) ) ) {
+ $_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..be8184518
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/ShipmentReturnItem.php
@@ -0,0 +1,31 @@
+ '',
+ );
+
+ 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..dfd69b951
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/ShippingProvider/Auto.php
@@ -0,0 +1,508 @@
+ 2,
+ 'label_minimum_shipment_weight' => 0.5,
+ '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' ) {
+ return $this->get_prop( 'label_default_shipment_weight', $context );
+ }
+
+ public function get_label_minimum_shipment_weight( $context = 'view' ) {
+ return $this->get_prop( 'label_minimum_shipment_weight', $context );
+ }
+
+ /**
+ * @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 ? 0 : wc_format_decimal( $weight ) ) );
+ }
+
+ public function set_label_minimum_shipment_weight( $weight ) {
+ $this->set_prop( 'label_minimum_shipment_weight', ( '' === $weight ? 0 : 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() {
+ $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',
+ 'custom_attributes' => array( 'data-show_if_label_auto_enable' => '' ),
+ '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() {
+ $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',
+ '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',
+ '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'] ] ) ) {
+ $props[ $field['id'] ] = 'no';
+ }
+ }
+
+ /**
+ * 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 ) ) ) {
+ if ( ! in_array( $new_key, $props['services'] ) ) {
+ $props['services'][] = $new_key;
+ }
+ unset( $props[ $key ] );
+ } else {
+ if ( ( $service_key = array_search( $new_key, $props['services'] ) ) !== 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..5a7065dd1
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/ShippingProvider/Helper.php
@@ -0,0 +1,190 @@
+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 );
+ }
+
+ /**
+ * 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..69f5bec0d
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/ShippingProvider/Method.php
@@ -0,0 +1,397 @@
+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;
+ }
+ }
+
+ if ( ! is_numeric( $id ) ) {
+ $expl = explode( ':', $id );
+ $instance_id = ( ( ! empty( $expl ) && sizeof( $expl ) > 1 ) ? $expl[1] : 0 );
+ $id = ( ( ! empty( $expl ) && sizeof( $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 $this->is_placeholder === true;
+ }
+
+ /**
+ * 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();
+ $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' ) ) ) {
+ $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..22ce09f12
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/ShippingProvider/MethodPlaceholder.php
@@ -0,0 +1,24 @@
+ true,
+ 'title' => '',
+ 'name' => '',
+ 'description' => '',
+ 'supports_customer_returns' => false,
+ 'supports_guest_returns' => false,
+ 'return_manual_confirmation' => true,
+ 'return_instructions' => '',
+ 'tracking_url_placeholder' => '',
+ 'tracking_desc_placeholder' => '',
+ );
+
+ /**
+ * 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 '';
+ }
+
+ /**
+ * 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 $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;
+ }
+
+ public function get_address_prop( $prop, $type = 'shipper' ) {
+ $key = "woocommerce_gzd_shipments_{$type}_address_{$prop}";
+ $value = get_option( $key, '' );
+
+ if ( 'return' === $type && '' === $value ) {
+ $value = get_option( "woocommerce_gzd_shipments_shipper_address_{$prop}" );
+ }
+
+ return $value;
+ }
+
+ 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_first_name() . ' ' . $this->get_shipper_last_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_2() {
+ return $this->get_address_prop( 'address_2' );
+ }
+
+ public function get_shipper_street() {
+ $split = wc_gzd_split_shipment_street( $this->get_shipper_address() );
+
+ return $split['street'];
+ }
+
+ public function get_shipper_street_number() {
+ $split = wc_gzd_split_shipment_street( $this->get_shipper_address() );
+
+ return $split['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_country() {
+ return $this->get_address_prop( 'country' );
+ }
+
+ 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_first_name() . ' ' . $this->get_return_last_name();
+ }
+
+ 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() {
+ $split = wc_gzd_split_shipment_street( $this->get_return_address() );
+
+ return $split['street'];
+ }
+
+ public function get_return_street_number() {
+ $split = wc_gzd_split_shipment_street( $this->get_return_address() );
+
+ return $split['number'];
+ }
+
+ 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() {
+ return $this->get_address_prop( 'country', 'return' );
+ }
+
+ 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' ) ) || ! 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 ) {
+
+ $tracking_desc = '';
+ $tracking_id = $shipment->get_tracking_id();
+
+ if ( '' !== $this->get_tracking_desc_placeholder() && ! empty( $tracking_id ) ) {
+ $placeholders = $this->get_tracking_placeholders( $shipment );
+ $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 );
+ }
+
+ protected function set_prop( $prop, $value ) {
+ parent::set_prop( $prop, $value );
+ }
+
+ /**
+ * @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() {
+ $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' => '',
+ '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 ) {}
+ }
+
+ public function get_settings( $section = '' ) {
+ $settings = array();
+
+ if ( '' === $section || 'general' === $section ) {
+ $settings = $this->get_general_settings();
+ } elseif( 'returns' === $section ) {
+ $settings = $this->get_return_settings();
+ } elseif( is_callable( array( $this, "get_{$section}_settings" ) ) ) {
+ $settings = $this->{"get_{$section}_settings"}();
+ }
+
+ /**
+ * 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 );
+ }
+
+ protected function get_return_settings() {
+ $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' ) . '',
+ '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() {
+ $settings = array();
+
+ foreach( array_keys( $this->get_setting_sections() ) as $section ) {
+ $settings[ $section ] = $this->get_settings( $section );
+ }
+
+ return $settings;
+ }
+
+ public function get_shipping_method_settings() {
+ $settings = $this->get_all_settings();
+ $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 : 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' ) ) && false !== $setting['allow_override'] ) {
+ $include = true;
+ } elseif( in_array( $setting['type'], array( 'title', 'sectionend' ) ) ) {
+ $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' ), $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;
+ }
+
+ public function save() {
+ return parent::save();
+ }
+
+ /**
+ * @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..6fd7ffca4
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/SimpleShipment.php
@@ -0,0 +1,382 @@
+ 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->get_address( 'shipping' ), array( 'email' => $order->get_billing_email(), 'phone' => $order->get_billing_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->get_shipping_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' => $this->calculate_additional_total( $order ),
+ ) );
+
+ /**
+ * 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;
+ }
+
+ /**
+ * @param WC_Order $order
+ */
+ protected function calculate_additional_total( $order ) {
+ $fees_total = 0;
+ $additional_total = 0;
+
+ // Sum fee costs.
+ foreach ( $order->get_fees() as $item ) {
+ $fees_total += ( $item->get_total() + $item->get_total_tax() );
+ }
+
+ $additional_total = $fees_total + $order->get_shipping_total() + $order->get_shipping_tax();
+
+ return $additional_total;
+ }
+
+ /**
+ * 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..3e84d0cfd
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/Validation.php
@@ -0,0 +1,215 @@
+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 ( 'shipped' === $shipment_order->get_shipping_status() ) {
+
+ /**
+ * 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', current_time( 'timestamp', true ) );
+ $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 ( self::$current_refund_parent_order !== false ) {
+
+ 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_id ) {
+ if ( $order_shipment = wc_gzd_get_shipment_order( $order_id ) ) {
+ $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 ) {}
+ }
+
+ 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 && is_ajax() && isset( $_REQUEST['action'] ) && isset( $_REQUEST['order_id'] ) && strpos( $_REQUEST['action'], 'woocommerce_' ) !== false ) {
+ $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..87d044101
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/src/WPMLHelper.php
@@ -0,0 +1,122 @@
+ $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 ShippingProvider $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 ShippingProvider $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..5dcd06ebe
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/templates/emails/admin-new-return-shipment-request.php
@@ -0,0 +1,60 @@
+
+
+
+ get_formatted_sender_full_name() ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
+
+
+
+ get_billing_first_name() ); ?>
+
+
+ get_order_number() ); ?>
+
+
+
+
+
+
+
+
+
+
+ get_billing_first_name() ); ?>
+
+
+
+
+
+
+
+ get_billing_first_name() ); ?>
+
+
+
+
+
+
+
+ get_billing_first_name() ); ?>
+
+
+
+
+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..753efff2d
--- /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..6581668aa
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/templates/emails/email-shipment-details.php
@@ -0,0 +1,84 @@
+
+
+
+ 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( '[%s #%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..7cf680f65
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/templates/emails/email-shipment-items.php
@@ -0,0 +1,113 @@
+ $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..e6ce55afe
--- /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..eb1959279
--- /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";
+
+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' ), $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..23c84abbb
--- /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";
+
+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..5d650156d
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/templates/emails/plain/customer-return-shipment.php
@@ -0,0 +1,48 @@
+get_billing_first_name() ) ) . "\n\n";
+
+
+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..4bfd87496
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/templates/emails/plain/customer-shipment.php
@@ -0,0 +1,49 @@
+get_billing_first_name() ) ) . "\n\n";
+
+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-return-shipment-instructions.php b/packages/woocommerce-germanized-shipments/templates/emails/plain/email-return-shipment-instructions.php
new file mode 100644
index 000000000..9b300a8a2
--- /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..58dec1adc
--- /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"; // WPCS: XSS ok.
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..4881df925
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/templates/emails/plain/email-shipment-details.php
@@ -0,0 +1,43 @@
+get_type() ) ) : sprintf( _x( '[%s #%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..ab14f5d3d
--- /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 apply_filters( 'woocommerce_gzd_shipment_item_name', $item->get_name(), $item, false );
+
+ if ( $show_sku && $sku ) {
+ echo ' (#' . $sku . ')';
+ }
+
+ /* This filter is documented in templates/emails/email-shipment-items.php */
+ echo ' X ' . 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..615c9edfd
--- /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' ) ) . ' ' . 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() ) . "\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..f23fab4f6
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/templates/global/empty.php
@@ -0,0 +1,21 @@
+
diff --git a/packages/woocommerce-germanized-shipments/templates/global/form-return-request.php b/packages/woocommerce-germanized-shipments/templates/global/form-return-request.php
new file mode 100644
index 000000000..f305ea694
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/templates/global/form-return-request.php
@@ -0,0 +1,51 @@
+
+
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..8209c82d1
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/templates/myaccount/add-return-shipment.php
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
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..c5eca7605
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/templates/myaccount/order-shipments.php
@@ -0,0 +1,45 @@
+
+
+
+
+
+ '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..e77167981
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/templates/myaccount/shipments.php
@@ -0,0 +1,112 @@
+
+
+
+
+
+ $column_name ) : ?>
+
+
+
+
+
+
+ get_item_count();
+ ?>
+
+ get_type() ) as $column_id => $column_name ) : ?>
+
+
+
+
+
+
+ get_type() ), $shipment->get_shipment_number() ) ); ?>
+
+
+
+ get_date_created() ) ); ?>
+
+
+ get_status() ) ); ?>
+
+ get_tracking_url() && ! $shipment->has_status( 'delivered' ) ) : ?>
+
+
+
+
+
+ $action ) { // phpcs:ignore WordPress.WP.GlobalVariablesOverride.OverrideProhibited
+ echo '' . esc_html( $action['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..b10ce3268
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/templates/shipment/add-return-shipment-item.php
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+ 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 ', $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_order_item() ) as $reason ) : ?>
+ get_reason(); ?>
+
+
+
+
+
+ 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..4a722ad0d
--- /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() ) : ?>
+ 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..99f795814
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/templates/shipment/shipment-details-item.php
@@ -0,0 +1,92 @@
+
+
+
+
+ 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 ', $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..2b252e739
--- /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..8612a5d3e
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/templates/shipment/shipment-details.php
@@ -0,0 +1,121 @@
+get_order();
+$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..edbbc6975
--- /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..638fb71b0
--- /dev/null
+++ b/packages/woocommerce-germanized-shipments/woocommerce-germanized-shipments.php
@@ -0,0 +1,72 @@
+
+
+
+ composer install',
+ '' . esc_html( str_replace( ABSPATH, '', __DIR__ ) ) . '
'
+ );
+ ?>
+
+
+ 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( '' );
+
+ $( '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..d90f16865
--- /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,self.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(" ")+"
"),s("html, body").animate({scrollTop:o.getSettingsWrapper().offset().top-100},1e3)},validate:function(e){var t=a.admin,o=!0,i=e.attr("id"),r="_code"===i.substr(i.length-5),i=e.val();return e.data("validate")?"integer"===e.data("validate")&&(i=parseInt(i),isNaN(i)&&(o=!1)):t.isExpertMode()&&r&&""===i&&(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"),t="_code"===e.substr(e.length-5),e=s(this).parents("tr").find("td");e.find(".wc-ts-error").remove(),o.validate(s(this))||(s(this).addClass("wc-ts-has-error"),t=t?o.params.i18n_error_mandatory:s(this).data("validate-msg"),e.append(''+t+" "),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/composer.json b/packages/woocommerce-trusted-shops/composer.json
new file mode 100644
index 000000000..9deecae82
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/composer.json
@@ -0,0 +1,28 @@
+{
+ "name": "vendidero/woocommerce-trusted-shops",
+ "description": "Trustbadge Reviews for WooCommerce.",
+ "homepage": "https://github.com/vendidero/woocommerce-trusted-shops",
+ "license": "GPL-3.0-or-later",
+ "type": "wordpress-plugin",
+ "prefer-stable": true,
+ "minimum-stability": "dev",
+ "require": {
+ "automattic/jetpack-autoloader": "^2.2.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "6.5.14"
+ },
+ "scripts": {
+ "post-install-cmd": [
+ "composer dump-autoload"
+ ],
+ "post-update-cmd": [
+ "composer dump-autoload"
+ ]
+ },
+ "autoload": {
+ "psr-4": {
+ "Vendidero\\TrustedShops\\": "src"
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/woocommerce-trusted-shops/composer.lock b/packages/woocommerce-trusted-shops/composer.lock
new file mode 100644
index 000000000..9d96340ac
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/composer.lock
@@ -0,0 +1,1737 @@
+{
+ "_readme": [
+ "This file locks the dependencies of your project to a known state",
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
+ "This file is @generated automatically"
+ ],
+ "content-hash": "afaceafbf78e093ec63013e98b62f10d",
+ "packages": [
+ {
+ "name": "automattic/jetpack-autoloader",
+ "version": "v2.5.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Automattic/jetpack-autoloader.git",
+ "reference": "7945e862473e39f05e6f698f1598ea30a12e5965"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Automattic/jetpack-autoloader/zipball/7945e862473e39f05e6f698f1598ea30a12e5965",
+ "reference": "7945e862473e39f05e6f698f1598ea30a12e5965",
+ "shasum": ""
+ },
+ "require": {
+ "composer-plugin-api": "^1.1 || ^2.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5"
+ },
+ "type": "composer-plugin",
+ "extra": {
+ "class": "Automattic\\Jetpack\\Autoloader\\CustomAutoloaderPlugin"
+ },
+ "autoload": {
+ "classmap": [
+ "src/AutoloadGenerator.php"
+ ],
+ "psr-4": {
+ "Automattic\\Jetpack\\Autoloader\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "GPL-2.0-or-later"
+ ],
+ "description": "Creates a custom autoloader for a plugin or theme.",
+ "support": {
+ "source": "https://github.com/Automattic/jetpack-autoloader/tree/v2.5.0"
+ },
+ "time": "2020-10-08T19:51:11+00:00"
+ }
+ ],
+ "packages-dev": [
+ {
+ "name": "doctrine/instantiator",
+ "version": "1.3.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/instantiator.git",
+ "reference": "f350df0268e904597e3bd9c4685c53e0e333feea"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/instantiator/zipball/f350df0268e904597e3bd9c4685c53e0e333feea",
+ "reference": "f350df0268e904597e3bd9c4685c53e0e333feea",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1 || ^8.0"
+ },
+ "require-dev": {
+ "doctrine/coding-standard": "^6.0",
+ "ext-pdo": "*",
+ "ext-phar": "*",
+ "phpbench/phpbench": "^0.13",
+ "phpstan/phpstan-phpunit": "^0.11",
+ "phpstan/phpstan-shim": "^0.11",
+ "phpunit/phpunit": "^7.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.2.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Marco Pivetta",
+ "email": "ocramius@gmail.com",
+ "homepage": "http://ocramius.github.com/"
+ }
+ ],
+ "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
+ "homepage": "https://www.doctrine-project.org/projects/instantiator.html",
+ "keywords": [
+ "constructor",
+ "instantiate"
+ ],
+ "support": {
+ "issues": "https://github.com/doctrine/instantiator/issues",
+ "source": "https://github.com/doctrine/instantiator/tree/1.3.x"
+ },
+ "funding": [
+ {
+ "url": "https://www.doctrine-project.org/sponsorship.html",
+ "type": "custom"
+ },
+ {
+ "url": "https://www.patreon.com/phpdoctrine",
+ "type": "patreon"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2020-05-29T17:27:14+00:00"
+ },
+ {
+ "name": "myclabs/deep-copy",
+ "version": "1.10.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/myclabs/DeepCopy.git",
+ "reference": "969b211f9a51aa1f6c01d1d2aef56d3bd91598e5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/969b211f9a51aa1f6c01d1d2aef56d3bd91598e5",
+ "reference": "969b211f9a51aa1f6c01d1d2aef56d3bd91598e5",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1 || ^8.0"
+ },
+ "replace": {
+ "myclabs/deep-copy": "self.version"
+ },
+ "require-dev": {
+ "doctrine/collections": "^1.0",
+ "doctrine/common": "^2.6",
+ "phpunit/phpunit": "^7.1"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "DeepCopy\\": "src/DeepCopy/"
+ },
+ "files": [
+ "src/DeepCopy/deep_copy.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Create deep copies (clones) of your objects",
+ "keywords": [
+ "clone",
+ "copy",
+ "duplicate",
+ "object",
+ "object graph"
+ ],
+ "support": {
+ "issues": "https://github.com/myclabs/DeepCopy/issues",
+ "source": "https://github.com/myclabs/DeepCopy/tree/1.x"
+ },
+ "funding": [
+ {
+ "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2020-06-29T13:22:24+00:00"
+ },
+ {
+ "name": "phar-io/manifest",
+ "version": "1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phar-io/manifest.git",
+ "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phar-io/manifest/zipball/2df402786ab5368a0169091f61a7c1e0eb6852d0",
+ "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-phar": "*",
+ "phar-io/version": "^1.0.1",
+ "php": "^5.6 || ^7.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Heuer",
+ "email": "sebastian@phpeople.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
+ "support": {
+ "issues": "https://github.com/phar-io/manifest/issues",
+ "source": "https://github.com/phar-io/manifest/tree/master"
+ },
+ "time": "2017-03-05T18:14:27+00:00"
+ },
+ {
+ "name": "phar-io/version",
+ "version": "1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phar-io/version.git",
+ "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df",
+ "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.6 || ^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Heuer",
+ "email": "sebastian@phpeople.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "Library for handling version information and constraints",
+ "support": {
+ "issues": "https://github.com/phar-io/version/issues",
+ "source": "https://github.com/phar-io/version/tree/master"
+ },
+ "time": "2017-03-05T17:38:23+00:00"
+ },
+ {
+ "name": "phpdocumentor/reflection-common",
+ "version": "2.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
+ "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b",
+ "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2 || ^8.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-2.x": "2.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "phpDocumentor\\Reflection\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jaap van Otterdijk",
+ "email": "opensource@ijaap.nl"
+ }
+ ],
+ "description": "Common reflection classes used by phpdocumentor to reflect the code structure",
+ "homepage": "http://www.phpdoc.org",
+ "keywords": [
+ "FQSEN",
+ "phpDocumentor",
+ "phpdoc",
+ "reflection",
+ "static analysis"
+ ],
+ "support": {
+ "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues",
+ "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x"
+ },
+ "time": "2020-06-27T09:03:43+00:00"
+ },
+ {
+ "name": "phpdocumentor/reflection-docblock",
+ "version": "5.2.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
+ "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/069a785b2141f5bcf49f3e353548dc1cce6df556",
+ "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556",
+ "shasum": ""
+ },
+ "require": {
+ "ext-filter": "*",
+ "php": "^7.2 || ^8.0",
+ "phpdocumentor/reflection-common": "^2.2",
+ "phpdocumentor/type-resolver": "^1.3",
+ "webmozart/assert": "^1.9.1"
+ },
+ "require-dev": {
+ "mockery/mockery": "~1.3.2"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "phpDocumentor\\Reflection\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Mike van Riel",
+ "email": "me@mikevanriel.com"
+ },
+ {
+ "name": "Jaap van Otterdijk",
+ "email": "account@ijaap.nl"
+ }
+ ],
+ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
+ "support": {
+ "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
+ "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/master"
+ },
+ "time": "2020-09-03T19:13:55+00:00"
+ },
+ {
+ "name": "phpdocumentor/type-resolver",
+ "version": "1.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpDocumentor/TypeResolver.git",
+ "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0",
+ "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2 || ^8.0",
+ "phpdocumentor/reflection-common": "^2.0"
+ },
+ "require-dev": {
+ "ext-tokenizer": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-1.x": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "phpDocumentor\\Reflection\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Mike van Riel",
+ "email": "me@mikevanriel.com"
+ }
+ ],
+ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
+ "support": {
+ "issues": "https://github.com/phpDocumentor/TypeResolver/issues",
+ "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.4.0"
+ },
+ "time": "2020-09-17T18:55:26+00:00"
+ },
+ {
+ "name": "phpspec/prophecy",
+ "version": "v1.10.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpspec/prophecy.git",
+ "reference": "451c3cd1418cf640de218914901e51b064abb093"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpspec/prophecy/zipball/451c3cd1418cf640de218914901e51b064abb093",
+ "reference": "451c3cd1418cf640de218914901e51b064abb093",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/instantiator": "^1.0.2",
+ "php": "^5.3|^7.0",
+ "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0",
+ "sebastian/comparator": "^1.2.3|^2.0|^3.0|^4.0",
+ "sebastian/recursion-context": "^1.0|^2.0|^3.0|^4.0"
+ },
+ "require-dev": {
+ "phpspec/phpspec": "^2.5 || ^3.2",
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.10.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Prophecy\\": "src/Prophecy"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Konstantin Kudryashov",
+ "email": "ever.zet@gmail.com",
+ "homepage": "http://everzet.com"
+ },
+ {
+ "name": "Marcello Duarte",
+ "email": "marcello.duarte@gmail.com"
+ }
+ ],
+ "description": "Highly opinionated mocking framework for PHP 5.3+",
+ "homepage": "https://github.com/phpspec/prophecy",
+ "keywords": [
+ "Double",
+ "Dummy",
+ "fake",
+ "mock",
+ "spy",
+ "stub"
+ ],
+ "support": {
+ "issues": "https://github.com/phpspec/prophecy/issues",
+ "source": "https://github.com/phpspec/prophecy/tree/v1.10.3"
+ },
+ "time": "2020-03-05T15:02:03+00:00"
+ },
+ {
+ "name": "phpunit/php-code-coverage",
+ "version": "5.3.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
+ "reference": "c89677919c5dd6d3b3852f230a663118762218ac"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/c89677919c5dd6d3b3852f230a663118762218ac",
+ "reference": "c89677919c5dd6d3b3852f230a663118762218ac",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-xmlwriter": "*",
+ "php": "^7.0",
+ "phpunit/php-file-iterator": "^1.4.2",
+ "phpunit/php-text-template": "^1.2.1",
+ "phpunit/php-token-stream": "^2.0.1",
+ "sebastian/code-unit-reverse-lookup": "^1.0.1",
+ "sebastian/environment": "^3.0",
+ "sebastian/version": "^2.0.1",
+ "theseer/tokenizer": "^1.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.0"
+ },
+ "suggest": {
+ "ext-xdebug": "^2.5.5"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.3.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
+ "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
+ "keywords": [
+ "coverage",
+ "testing",
+ "xunit"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
+ "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/5.3"
+ },
+ "time": "2018-04-06T15:36:58+00:00"
+ },
+ {
+ "name": "phpunit/php-file-iterator",
+ "version": "1.4.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
+ "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4",
+ "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.4.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sb@sebastian-bergmann.de",
+ "role": "lead"
+ }
+ ],
+ "description": "FilterIterator implementation that filters files based on a list of suffixes.",
+ "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
+ "keywords": [
+ "filesystem",
+ "iterator"
+ ],
+ "support": {
+ "irc": "irc://irc.freenode.net/phpunit",
+ "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
+ "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/1.4.5"
+ },
+ "time": "2017-11-27T13:52:08+00:00"
+ },
+ {
+ "name": "phpunit/php-text-template",
+ "version": "1.2.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-text-template.git",
+ "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
+ "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Simple template engine.",
+ "homepage": "https://github.com/sebastianbergmann/php-text-template/",
+ "keywords": [
+ "template"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-text-template/issues",
+ "source": "https://github.com/sebastianbergmann/php-text-template/tree/1.2.1"
+ },
+ "time": "2015-06-21T13:50:34+00:00"
+ },
+ {
+ "name": "phpunit/php-timer",
+ "version": "1.0.9",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-timer.git",
+ "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
+ "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3.3 || ^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sb@sebastian-bergmann.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Utility class for timing",
+ "homepage": "https://github.com/sebastianbergmann/php-timer/",
+ "keywords": [
+ "timer"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-timer/issues",
+ "source": "https://github.com/sebastianbergmann/php-timer/tree/master"
+ },
+ "time": "2017-02-26T11:10:40+00:00"
+ },
+ {
+ "name": "phpunit/php-token-stream",
+ "version": "2.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-token-stream.git",
+ "reference": "791198a2c6254db10131eecfe8c06670700904db"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db",
+ "reference": "791198a2c6254db10131eecfe8c06670700904db",
+ "shasum": ""
+ },
+ "require": {
+ "ext-tokenizer": "*",
+ "php": "^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.2.4"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Wrapper around PHP's tokenizer extension.",
+ "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
+ "keywords": [
+ "tokenizer"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-token-stream/issues",
+ "source": "https://github.com/sebastianbergmann/php-token-stream/tree/master"
+ },
+ "abandoned": true,
+ "time": "2017-11-27T05:48:46+00:00"
+ },
+ {
+ "name": "phpunit/phpunit",
+ "version": "6.5.14",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/phpunit.git",
+ "reference": "bac23fe7ff13dbdb461481f706f0e9fe746334b7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/bac23fe7ff13dbdb461481f706f0e9fe746334b7",
+ "reference": "bac23fe7ff13dbdb461481f706f0e9fe746334b7",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-json": "*",
+ "ext-libxml": "*",
+ "ext-mbstring": "*",
+ "ext-xml": "*",
+ "myclabs/deep-copy": "^1.6.1",
+ "phar-io/manifest": "^1.0.1",
+ "phar-io/version": "^1.0",
+ "php": "^7.0",
+ "phpspec/prophecy": "^1.7",
+ "phpunit/php-code-coverage": "^5.3",
+ "phpunit/php-file-iterator": "^1.4.3",
+ "phpunit/php-text-template": "^1.2.1",
+ "phpunit/php-timer": "^1.0.9",
+ "phpunit/phpunit-mock-objects": "^5.0.9",
+ "sebastian/comparator": "^2.1",
+ "sebastian/diff": "^2.0",
+ "sebastian/environment": "^3.1",
+ "sebastian/exporter": "^3.1",
+ "sebastian/global-state": "^2.0",
+ "sebastian/object-enumerator": "^3.0.3",
+ "sebastian/resource-operations": "^1.0",
+ "sebastian/version": "^2.0.1"
+ },
+ "conflict": {
+ "phpdocumentor/reflection-docblock": "3.0.2",
+ "phpunit/dbunit": "<3.0"
+ },
+ "require-dev": {
+ "ext-pdo": "*"
+ },
+ "suggest": {
+ "ext-xdebug": "*",
+ "phpunit/php-invoker": "^1.1"
+ },
+ "bin": [
+ "phpunit"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "6.5.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "The PHP Unit Testing framework.",
+ "homepage": "https://phpunit.de/",
+ "keywords": [
+ "phpunit",
+ "testing",
+ "xunit"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/phpunit/issues",
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/6.5.14"
+ },
+ "time": "2019-02-01T05:22:47+00:00"
+ },
+ {
+ "name": "phpunit/phpunit-mock-objects",
+ "version": "5.0.10",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
+ "reference": "cd1cf05c553ecfec36b170070573e540b67d3f1f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/cd1cf05c553ecfec36b170070573e540b67d3f1f",
+ "reference": "cd1cf05c553ecfec36b170070573e540b67d3f1f",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/instantiator": "^1.0.5",
+ "php": "^7.0",
+ "phpunit/php-text-template": "^1.2.1",
+ "sebastian/exporter": "^3.1"
+ },
+ "conflict": {
+ "phpunit/phpunit": "<6.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.5.11"
+ },
+ "suggest": {
+ "ext-soap": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Mock Object library for PHPUnit",
+ "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
+ "keywords": [
+ "mock",
+ "xunit"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/phpunit-mock-objects/issues",
+ "source": "https://github.com/sebastianbergmann/phpunit-mock-objects/tree/5.0.10"
+ },
+ "abandoned": true,
+ "time": "2018-08-09T05:50:03+00:00"
+ },
+ {
+ "name": "sebastian/code-unit-reverse-lookup",
+ "version": "1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
+ "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18",
+ "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.6 || ^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^5.7 || ^6.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Looks up which function or method a line of code belongs to",
+ "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
+ "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/master"
+ },
+ "time": "2017-03-04T06:30:41+00:00"
+ },
+ {
+ "name": "sebastian/comparator",
+ "version": "2.1.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/comparator.git",
+ "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/34369daee48eafb2651bea869b4b15d75ccc35f9",
+ "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0",
+ "sebastian/diff": "^2.0 || ^3.0",
+ "sebastian/exporter": "^3.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.4"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.1.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Volker Dusch",
+ "email": "github@wallbash.com"
+ },
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@2bepublished.at"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Provides the functionality to compare PHP values for equality",
+ "homepage": "https://github.com/sebastianbergmann/comparator",
+ "keywords": [
+ "comparator",
+ "compare",
+ "equality"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/comparator/issues",
+ "source": "https://github.com/sebastianbergmann/comparator/tree/master"
+ },
+ "time": "2018-02-01T13:46:46+00:00"
+ },
+ {
+ "name": "sebastian/diff",
+ "version": "2.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/diff.git",
+ "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/347c1d8b49c5c3ee30c7040ea6fc446790e6bddd",
+ "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.2"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Kore Nordmann",
+ "email": "mail@kore-nordmann.de"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Diff implementation",
+ "homepage": "https://github.com/sebastianbergmann/diff",
+ "keywords": [
+ "diff"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/diff/issues",
+ "source": "https://github.com/sebastianbergmann/diff/tree/master"
+ },
+ "time": "2017-08-03T08:09:46+00:00"
+ },
+ {
+ "name": "sebastian/environment",
+ "version": "3.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/environment.git",
+ "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5",
+ "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.1.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Provides functionality to handle HHVM/PHP environments",
+ "homepage": "http://www.github.com/sebastianbergmann/environment",
+ "keywords": [
+ "Xdebug",
+ "environment",
+ "hhvm"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/environment/issues",
+ "source": "https://github.com/sebastianbergmann/environment/tree/master"
+ },
+ "time": "2017-07-01T08:51:00+00:00"
+ },
+ {
+ "name": "sebastian/exporter",
+ "version": "3.1.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/exporter.git",
+ "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/68609e1261d215ea5b21b7987539cbfbe156ec3e",
+ "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0",
+ "sebastian/recursion-context": "^3.0"
+ },
+ "require-dev": {
+ "ext-mbstring": "*",
+ "phpunit/phpunit": "^6.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.1.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Volker Dusch",
+ "email": "github@wallbash.com"
+ },
+ {
+ "name": "Adam Harvey",
+ "email": "aharvey@php.net"
+ },
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@gmail.com"
+ }
+ ],
+ "description": "Provides the functionality to export PHP variables for visualization",
+ "homepage": "http://www.github.com/sebastianbergmann/exporter",
+ "keywords": [
+ "export",
+ "exporter"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/exporter/issues",
+ "source": "https://github.com/sebastianbergmann/exporter/tree/master"
+ },
+ "time": "2019-09-14T09:02:43+00:00"
+ },
+ {
+ "name": "sebastian/global-state",
+ "version": "2.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/global-state.git",
+ "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4",
+ "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.0"
+ },
+ "suggest": {
+ "ext-uopz": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Snapshotting of global state",
+ "homepage": "http://www.github.com/sebastianbergmann/global-state",
+ "keywords": [
+ "global state"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/global-state/issues",
+ "source": "https://github.com/sebastianbergmann/global-state/tree/2.0.0"
+ },
+ "time": "2017-04-27T15:39:26+00:00"
+ },
+ {
+ "name": "sebastian/object-enumerator",
+ "version": "3.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/object-enumerator.git",
+ "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5",
+ "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0",
+ "sebastian/object-reflector": "^1.1.1",
+ "sebastian/recursion-context": "^3.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Traverses array structures and object graphs to enumerate all referenced objects",
+ "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
+ "source": "https://github.com/sebastianbergmann/object-enumerator/tree/master"
+ },
+ "time": "2017-08-03T12:35:26+00:00"
+ },
+ {
+ "name": "sebastian/object-reflector",
+ "version": "1.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/object-reflector.git",
+ "reference": "773f97c67f28de00d397be301821b06708fca0be"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be",
+ "reference": "773f97c67f28de00d397be301821b06708fca0be",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.1-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Allows reflection of object attributes, including inherited and non-public ones",
+ "homepage": "https://github.com/sebastianbergmann/object-reflector/",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/object-reflector/issues",
+ "source": "https://github.com/sebastianbergmann/object-reflector/tree/master"
+ },
+ "time": "2017-03-29T09:07:27+00:00"
+ },
+ {
+ "name": "sebastian/recursion-context",
+ "version": "3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/recursion-context.git",
+ "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8",
+ "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Adam Harvey",
+ "email": "aharvey@php.net"
+ }
+ ],
+ "description": "Provides functionality to recursively process PHP variables",
+ "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/recursion-context/issues",
+ "source": "https://github.com/sebastianbergmann/recursion-context/tree/master"
+ },
+ "time": "2017-03-03T06:23:57+00:00"
+ },
+ {
+ "name": "sebastian/resource-operations",
+ "version": "1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/resource-operations.git",
+ "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52",
+ "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.6.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Provides a list of PHP built-in functions that operate on resources",
+ "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/resource-operations/issues",
+ "source": "https://github.com/sebastianbergmann/resource-operations/tree/master"
+ },
+ "time": "2015-07-28T20:34:47+00:00"
+ },
+ {
+ "name": "sebastian/version",
+ "version": "2.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/version.git",
+ "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019",
+ "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.6"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library that helps with managing the version number of Git-hosted PHP projects",
+ "homepage": "https://github.com/sebastianbergmann/version",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/version/issues",
+ "source": "https://github.com/sebastianbergmann/version/tree/master"
+ },
+ "time": "2016-10-03T07:35:21+00:00"
+ },
+ {
+ "name": "symfony/polyfill-ctype",
+ "version": "v1.20.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-ctype.git",
+ "reference": "f4ba089a5b6366e453971d3aad5fe8e897b37f41"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f4ba089a5b6366e453971d3aad5fe8e897b37f41",
+ "reference": "f4ba089a5b6366e453971d3aad5fe8e897b37f41",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "suggest": {
+ "ext-ctype": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.20-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Ctype\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Gert de Pagter",
+ "email": "BackEndTea@gmail.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for ctype functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "ctype",
+ "polyfill",
+ "portable"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.20.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2020-10-23T14:02:19+00:00"
+ },
+ {
+ "name": "theseer/tokenizer",
+ "version": "1.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/theseer/tokenizer.git",
+ "reference": "75a63c33a8577608444246075ea0af0d052e452a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/theseer/tokenizer/zipball/75a63c33a8577608444246075ea0af0d052e452a",
+ "reference": "75a63c33a8577608444246075ea0af0d052e452a",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-tokenizer": "*",
+ "ext-xmlwriter": "*",
+ "php": "^7.2 || ^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
+ "support": {
+ "issues": "https://github.com/theseer/tokenizer/issues",
+ "source": "https://github.com/theseer/tokenizer/tree/master"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/theseer",
+ "type": "github"
+ }
+ ],
+ "time": "2020-07-12T23:59:07+00:00"
+ },
+ {
+ "name": "webmozart/assert",
+ "version": "1.9.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/webmozart/assert.git",
+ "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/webmozart/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389",
+ "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3.3 || ^7.0 || ^8.0",
+ "symfony/polyfill-ctype": "^1.8"
+ },
+ "conflict": {
+ "phpstan/phpstan": "<0.12.20",
+ "vimeo/psalm": "<3.9.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.8.36 || ^7.5.13"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Webmozart\\Assert\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@gmail.com"
+ }
+ ],
+ "description": "Assertions to validate method input/output with nice error messages.",
+ "keywords": [
+ "assert",
+ "check",
+ "validate"
+ ],
+ "support": {
+ "issues": "https://github.com/webmozart/assert/issues",
+ "source": "https://github.com/webmozart/assert/tree/master"
+ },
+ "time": "2020-07-08T17:02:28+00:00"
+ }
+ ],
+ "aliases": [],
+ "minimum-stability": "dev",
+ "stability-flags": [],
+ "prefer-stable": true,
+ "prefer-lowest": false,
+ "platform": [],
+ "platform-dev": [],
+ "plugin-api-version": "2.0.0"
+}
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 000000000..06afcb3b9
Binary files /dev/null and b/packages/woocommerce-trusted-shops/i18n/languages/woocommerce-trusted-shops-de_DE.mo differ
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 000000000..4ea14e41a
Binary files /dev/null and b/packages/woocommerce-trusted-shops/i18n/languages/woocommerce-trusted-shops-de_DE_formal.mo differ
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 000000000..19ef22d77
Binary files /dev/null and b/packages/woocommerce-trusted-shops/i18n/languages/woocommerce-trusted-shops-fr_FR.mo differ
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"
+"strong> – 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..eb7f12628
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/includes/abstracts/abstract-wc-ts-compatibility.php
@@ -0,0 +1,82 @@
+ '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 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..809539023
--- /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() );
+ }
+
+ 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'] ) {
+ 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..867e495e6
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/includes/admin/views/html-notice-dependencies.php
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+ plugins_required as $plugin => $data ) : ?>
+
+ is_plugin_activated( $plugin ) ) : $missing_count++ ?>
+
+
+
+
+
+
+
+
">
+
+
+
+ is_plugin_outdated( $plugin ) ) : $version_count ++ ?>
+
+
+
+
+
+
+
+
- ' . $data[ 'version' ] . '' ); ?>
+
+
+
+
+
+ 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..328fe675e
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/includes/admin/views/html-notice-update.php
@@ -0,0 +1,21 @@
+
+
+
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..6e89e8dac
--- /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..2f37b9a8d
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/includes/admin/views/html-wpml-notice.php
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+ ' . $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..27d68d0d1
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-admin.php
@@ -0,0 +1,954 @@
+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' ) );
+
+ 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] ) ? $_POST[ $data_k ][$i] : null );
+ }
+
+ 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-germanized' ) ) );
+ 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-germanized' ) ) );
+
+ echo '
';
+ }
+
+ public function save_fields( $product ) {
+ if ( is_numeric( $product ) )
+ $product = wc_get_product( $product );
+
+ if ( isset( $_POST['_ts_gtin'] ) ) {
+ $product = wc_ts_set_crud_data( $product, '_ts_gtin', wc_clean( $_POST['_ts_gtin'] ) );
+ }
+
+ if ( isset( $_POST['_ts_mpn'] ) ) {
+ $product = wc_ts_set_crud_data( $product, '_ts_mpn', wc_clean( $_POST['_ts_mpn'] ) );
+ }
+ }
+
+ 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() ) ) {
+ $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' ) ) ) {
+ $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 %d and %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 %d and %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 ) ) {
+ $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();
+ ?>
+
+ base->option_prefix . 'trusted_shops_id'] ) && $_POST['woocommerce_' . $this->base->option_prefix . 'trusted_shops_id'] != $this->base->id ) {
+ 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' );
+ }
+
+ // 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'] ) || $_GET['action'] != 'wc_' . $this->base->option_prefix . 'trusted-shops-export' || ( isset( $_GET['action'] ) && $_GET['action'] == 'wc_' . $this->base->option_prefix . 'trusted-shops-export' && ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'wc_' . $this->base->option_prefix . 'trusted-shops-export' ) ) )
+ 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( $_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( $_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">' . _x( 'My Trusted Shops account', '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 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..0e8dd7e86
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-core.php
@@ -0,0 +1,464 @@
+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 ( get_option( '_wc_ts_needs_update' ) == 1 ) {
+
+ if ( current_user_can( 'manage_woocommerce' ) ) {
+ wp_enqueue_style( 'woocommerce-activation', plugins_url( '/assets/css/activation.css', WC_PLUGIN_FILE ) );
+ wp_enqueue_style( 'woocommerce-ts-activation', plugins_url( '/assets/css/activation.css', WC_TRUSTED_SHOPS_PLUGIN_FILE ) );
+
+ 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 ( get_option( '_wc_ts_needs_update' ) == 1 ) {
+ 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'] ) {
+ $footer_text = sprintf( _x( 'If the App helped you, please leave a %s★★★★★%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'] ) {
+ 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() {
+ 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..c11fff6bd
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-review-exporter.php
@@ -0,0 +1,168 @@
+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' => _x( 'Order ID', 'trusted-shops', 'woocommerce-germanized' ),
+ 'date' => _x( 'Order date', 'trusted-shops', 'woocommerce-germanized' ),
+ 'days' => _x( '# Days', 'trusted-shops', 'woocommerce-germanized' ),
+ 'billing_email' => _x( 'Email', 'trusted-shops', 'woocommerce-germanized' ),
+ 'billing_first_name' => _x( 'First name', 'trusted-shops', 'woocommerce-germanized' ),
+ 'billing_last_name' => _x( 'Last name', 'trusted-shops', 'woocommerce-germanized' ),
+ ) );
+ }
+
+ 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' ) );
+ $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();
+ $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..d794d41b7
--- /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( $_GET['section'] ) : '';
+
+ // 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();
+ }
+
+ 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( $language );
+ }
+ }
+ }
+ }
+
+ /**
+ * Update Review Cache by grabbing information from xml file
+ */
+ public function update_reviews() {
+ $this->_update_reviews();
+
+ 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( $language );
+ }
+ }
+ }
+
+ protected function _update_reviews( $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( $language );
+ }
+
+ } else {
+ $this->_send_mails();
+ }
+ }
+
+ protected function _send_mails( $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(
+ '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..7857f48a8
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-shortcodes.php
@@ -0,0 +1,84 @@
+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 ) {
+ extract( shortcode_atts( array('width' => ''), $atts ) );
+
+ 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..6752bec00
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-template-hooks.php
@@ -0,0 +1,251 @@
+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() ) ) {
+ if ( is_product_category() ) {
+ $insert = true;
+ }
+ }
+
+ if ( in_array( 'home', $this->base->get_rich_snippets_locations() ) ) {
+ if ( function_exists( 'is_shop' ) && is_shop() ) {
+ $insert = true;
+ }
+ }
+
+ if ( in_array( 'product', $this->base->get_rich_snippets_locations() ) ) {
+ 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'] ) ) {
+
+ $order_id = absint( $_GET['order-id'] );
+ $code = wc_clean( $_GET['disable-review-reminder'] );
+
+ 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(
+ '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( sprintf( _x( 'Your review reminder e-mail has been cancelled successfully. Return to %s.', 'trusted-shops', 'woocommerce-germanized' ), '' . _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 );
+ }
+
+ $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 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' ) );
+ $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() ) ) {
+ 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' ) ) ) {
+ $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..e17bf409d
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops-widgets.php
@@ -0,0 +1,33 @@
+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..fc8dd10ea
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/includes/class-wc-trusted-shops.php
@@ -0,0 +1,659 @@
+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 ( $this->rich_snippets_category === 'yes' ) {
+ $locations[] = 'category';
+ }
+
+ if ( $this->rich_snippets_product === 'yes' ) {
+ $locations[] = 'product';
+ }
+
+ if ( $this->rich_snippets_home === 'yes' ) {
+ $locations[] = 'home';
+ }
+
+ return $locations;
+ }
+
+ public function is_trustbadge_enabled() {
+ return ( $this->trustbadge_enable === 'yes' && $this->id !== '' ? true : false );
+ }
+
+ /**
+ * Checks whether Trusted Shops Rich Snippets are enabled
+ *
+ * @return boolean
+ */
+ public function is_rich_snippets_enabled() {
+ return ( $this->rich_snippets_enable === 'yes' && $this->is_enabled() ? true : false );
+ }
+
+ /**
+ * Checks whether review widget is enabled
+ *
+ * @return boolean
+ */
+ public function is_review_widget_enabled() {
+ return ( $this->review_widget_enable === 'yes' && $this->is_enabled() ? true : false );
+ }
+
+ public function is_review_reminder_enabled() {
+ return ( $this->review_reminder_enable === 'yes' && $this->supports( 'reminder' ) && $this->is_enabled() ? true : false );
+ }
+
+ public function is_review_reminder_checkbox_enabled() {
+ return ( $this->review_reminder_checkbox === 'yes' && $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 ( $this->reviews_enable === 'yes' && $this->is_enabled() ? true : false );
+ }
+
+ public function is_product_sticker_enabled() {
+ return ( $this->is_product_reviews_enabled() && $this->product_sticker_enable === 'yes' ? true : false );
+ }
+
+ public function is_review_sticker_enabled() {
+ return $this->review_sticker_enable === 'yes' ? true : false;
+ }
+
+ public function is_product_widget_enabled() {
+ return ( $this->is_product_reviews_enabled() && $this->product_widget_enable === 'yes' ? true : false );
+ }
+
+ public function supports( $type ) {
+ return ( in_array( $type, $this->supports ) ? 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=' . urlencode( base64_encode( $email ) ) . '&shopOrderID=' . urlencode( base64_encode( $order_id ) );
+ }
+
+ /**
+ * 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 ( 'variation' === $product->get_type() ) {
+ if ( empty( $data ) ) {
+ $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();
+
+ return preg_replace('/^\h*\v+/m', '', strip_tags( $html ) );
+ }
+
+ public function get_script( $name, $replace = true, $args = array() ) {
+ $script = $this->get_template( $name );
+
+ if ( $this->integration_mode === 'expert' ) {
+ $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 ) {
+ $args = wp_parse_args( $args, array(
+ 'element' => $this->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 ) {
+
+ $args = wp_parse_args( $args, array(
+ 'element' => $this->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' => $this->trustbadge_variant === 'standard' ? '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..4d49092b9
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/includes/class-wc-ts-dependencies.php
@@ -0,0 +1,139 @@
+ 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__, _x( 'Cheatin’ huh?', 'trusted-shops', 'woocommerce-germanized' ), '1.0' );
+ }
+
+ /**
+ * Unserializing instances of this class is forbidden.
+ *
+ * @since 1.0
+ */
+ public function __wakeup() {
+ _doing_it_wrong( __FUNCTION__, _x( 'Cheatin’ 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 ) || 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 ( sizeof( $expl_main_ver ) == 2 && sizeof( $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..2e87b1c48
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/includes/class-wc-ts-install.php
@@ -0,0 +1,168 @@
+ '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'] ) ) {
+ 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..712feadae
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/includes/class-wc-ts-settings-handler.php
@@ -0,0 +1,70 @@
+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 output() {
+ global $current_section;
+
+ $settings = $this->get_settings();
+ $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();
+
+ 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..8e6afae03
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/includes/compatibility/class-wc-ts-compatibility-wpml-string-translation.php
@@ -0,0 +1,343 @@
+ 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'] ) ) {
+ $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;
+
+ return $WPML_String_Translation->get_current_string_language( $option );
+ }
+
+ 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 ) ) {
+ $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 ) ) {
+ $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..61c18977b
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/includes/emails/class-wc-ts-email-customer-trusted-shops.php
@@ -0,0 +1,159 @@
+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..b8fc50196
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/includes/updates/woocommerce-ts-update-3.0.0.php
@@ -0,0 +1,23 @@
+
diff --git a/packages/woocommerce-trusted-shops/includes/updates/woocommerce-ts-update-4.0.6.php b/packages/woocommerce-trusted-shops/includes/updates/woocommerce-ts-update-4.0.6.php
new file mode 100644
index 000000000..c4c3c4406
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/includes/updates/woocommerce-ts-update-4.0.6.php
@@ -0,0 +1,14 @@
+
diff --git a/packages/woocommerce-trusted-shops/includes/wc-ts-core-functions.php b/packages/woocommerce-trusted-shops/includes/wc-ts-core-functions.php
new file mode 100644
index 000000000..c097b5d64
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/includes/wc-ts-core-functions.php
@@ -0,0 +1,319 @@
+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..7b20bb3b6
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/includes/widgets/class-wc-trusted-shops-widget-review-sticker.php
@@ -0,0 +1,63 @@
+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 );
+
+ $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 $before_widget;
+
+ if ( $title )
+ echo $before_title . $title . $after_title;
+
+ echo '';
+
+ echo do_shortcode( '[trusted_shops_review_sticker element="' . $element . '"]' );
+
+ echo '
';
+
+ echo $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..364f66410
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/readme.txt
@@ -0,0 +1,149 @@
+=== 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.5
+WC requires at least: 3.4
+WC tested up to: 4.6
+Stable tag: 4.0.8
+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 ==
+
+The eTrusted Reviews Plugin for WooCommerce enables you to automatically collect seller reviews and product reviews from your happy customers. You can integrate the Trustbadge® within your store with one click and it will be displayed on every site of your store showing your overall score, your star ratings and three reviews when expanded. It also links to your profile on eTrusted where all reviews from your happy customers are displayed to improve your SEO. The Trustbadge® works with any web browser and on all devices. Your customers do not require any additional software.
+* Collect seller and product reviews automatically
+* Show your trustworthiness on your website by authentic reviews
+* Increase your conversion rates
+
+= Why customer reviews are highly important =
+
+„Reviews are the joint single biggest conversion factor along with price.“ — Jeff Bezos, CEO and founder of Amazon
+„In a networked world trust is the most important currency.“
— Eric Schmidt, Chairman of Google
+„According to Google, 70% of Americans now say they look at product reviews before making a purchase.“
+
+= eTrusted: Get Better Reviews =
+
+Trust, security and transparency are vital for success in the world of e-commerce. 90 % of decisions to buy online are based on these factors. People only buy from those they trust and if consumers can't trust an online store, they will go elsewhere. To succeed in internet sales and to boost their conversion rate, online traders need to show their potential customers how trustworthy they are.
+
+And this is precisely where eTrusted can help you. We support Woocommerce users with services that have been successfully applied for by 20,000+ of online retailers: Our customer review system allows you to collect, show and manage your customers’ feedback effortlessly!
+
+Get your account now!
+
+= Seller reviews + product reviews = Increase your conversion rate and get more sales =
+
+Seller reviews and product reviews complement each other in order to give your potential customers a positive attitude towards a purchase in your store. The Trustbadge offers both. Seller reviews show that your customers trust you and reinforce their feeling that they are at the right place to buy.
+
+Great product reviews convince them to buy a specific product. If you provide both kinds of reviews to your customers, a purchase is more likely to happen which means more sales for your store.
+
+Some customers experienced an uplift of up to 12.5 % in conversions, simply by using the Trustbadge. No matter to which country or on which device you sell - the Trustbadge is well prepared. It comes with 7 possible languages and is mobile-optimized - this means all common devices are supported.
+
+= Getting Started =
+
+With your WooCommerce store you can start in less than 66 seconds
+
+1. Sign up for a Trustbadge Reviews account .
+2. Install the Trustbadge Reviews Toolkit in your WooCommerce store
+3. Customize your Trustbadge in the backend of WooCommerce
+
+As promised, it´s easy like that. Welcome on board!
+
+== 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 ==
+
+= How can I become a Trusted Shops Member? =
+More information regarding your Trusted Shops Membership can be found [here](https://business.trustedshops.co.uk/).
+
+== Screenshots ==
+
+1. WooCommerce Trusted Shops Settings
+
+== Changelog ==
+
+= 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..66c2ecffd
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/src/Package.php
@@ -0,0 +1,110 @@
+
+
+ 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..8b0c2ad6d
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/templates/emails/cancel-review-reminder.php
@@ -0,0 +1,14 @@
+
+
+
+
' . _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..5c948fa35
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/templates/emails/customer-trusted-shops.php
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
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..87f33442c
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/templates/emails/plain/customer-trusted-shops.php
@@ -0,0 +1,32 @@
+trusted_shops->get_new_review_link( wc_ts_get_crud_data( $order, 'billing_email' ), wc_ts_get_crud_data( $order, 'id' ) ) . "\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 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..44561b422
--- /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..18a5744db
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/templates/trusted-shops/product-sticker.php
@@ -0,0 +1,19 @@
+get_product_skus( $post->ID );
+?>
+
+get_selector( 'product_sticker' ); ?>>
+
+
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..08d41768a
--- /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..1dd2927d2
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/templates/trusted-shops/product-widget.php
@@ -0,0 +1,23 @@
+ID );
+$plugin = isset( $plugin ) ? $plugin : WC_trusted_shops()->trusted_shops;
+$skus = $plugin->get_product_skus( $post->ID );
+?>
+
+get_selector( 'product_widget' ); ?>>
+
+
+
+
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..2f9890663
--- /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..dc0f2896e
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/templates/trusted-shops/review-sticker.php
@@ -0,0 +1,17 @@
+
+
+get_selector( 'review_sticker', $element ); ?>>
+
+
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..0f9afef14
--- /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..a92ee4755
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/templates/trusted-shops/rich-snippets.php
@@ -0,0 +1,16 @@
+
+
+
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..a2f229bcb
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/templates/trusted-shops/thankyou.php
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+ get_total(); ?>
+
+ get_payment_method_title(); ?>
+
+ is_product_reviews_enabled() ) : ?>
+ get_items() as $item_id => $item ) :
+
+ $org_product = $order->get_product_from_item( $item );
+ $parent_product = $org_product;
+
+ if ( ! $org_product )
+ continue;
+
+ // Currently not supporting reviews for variations
+ if ( $org_product->is_type( 'variation' ) )
+ $parent_product = wc_get_product( wc_ts_get_crud_data( $org_product, 'parent' ) );
+
+ ?>
+
+
+ get_product_image( $org_product ); ?>
+
+ get_sku() ? $parent_product->get_sku() : wc_ts_get_crud_data( $parent_product, 'id' ) ); ?>
+ get_product_gtin( $org_product ), $org_product ); ?>
+ get_product_brand( $parent_product ), $parent_product ); ?>
+ get_product_mpn( $org_product ), $org_product ); ?>
+
+
+
+
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..b6da7d249
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/templates/trusted-shops/trustbadge.php
@@ -0,0 +1,15 @@
+
+
+
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..55cdf898f
--- /dev/null
+++ b/packages/woocommerce-trusted-shops/woocommerce-trusted-shops.php
@@ -0,0 +1,73 @@
+
+
+
+ composer install',
+ '' . esc_html( str_replace( ABSPATH, '', __DIR__ ) ) . '
'
+ );
+ ?>
+
+
+