WooCommerce ESW: differenze tra le versioni
| (113 versioni intermedie di 4 utenti non mostrate) | |||
| Riga 1: | Riga 1: | ||
Il progetto prevede la creazione di un mini-sito con commerce integrato con Easy Store Web. | Il progetto prevede la creazione di un mini-sito con commerce integrato con Easy Store Web. | ||
== Ambiente di lavoro == | |||
=== Container === | |||
Abbiamo optato per un docker container così strutturato<br/> | Abbiamo optato per un docker container così strutturato<br/> | ||
<code>docker-compose.yml</code> | <code>docker-compose.yml</code> | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="yaml"> | ||
version: '3.9' | version: '3.9' | ||
| Riga 11: | Riga 11: | ||
db: | db: | ||
image: mysql: | image: mysql:8.3 | ||
ports: | ports: | ||
- 3306:3306 | - 3306:3306 | ||
| Riga 25: | Riga 25: | ||
depends_on: | depends_on: | ||
- db | - db | ||
build: | |||
context: ./ | |||
ports: | ports: | ||
- 8000:80 | - 8000:80 | ||
| Riga 33: | Riga 34: | ||
WORDPRESS_DB_PASSWORD: w3bm0b1l1 | WORDPRESS_DB_PASSWORD: w3bm0b1l1 | ||
WORDPRESS_DB_NAME: webmobili | WORDPRESS_DB_NAME: webmobili | ||
WORDPRESS_DEBUG: 1 | |||
TZ: "Europe/Rome" | |||
volumes: | volumes: | ||
- | - wordpress:/var/www/html | ||
volumes: | volumes: | ||
db: | db: | ||
wordpress: | |||
</syntaxhighlight> | |||
Punta al seguente '''Dockerfile''' che si occupa di configurare '''xdebug''' per PHP. | |||
<syntaxhighlight lang="docker"> | |||
FROM wordpress:6.6.2-apache | |||
RUN apt-get update && \ | |||
pecl install xdebug \ | |||
&& docker-php-ext-enable xdebug | |||
# Copy xdebug.ini to /usr/local/etc/php/conf.d/ | |||
COPY ./*.ini /usr/local/etc/php/conf.d/ | |||
# Copy plugin data to to /usr/src/wordpress/wp-content/plugins/ | |||
COPY --chown=www-data:www-data ./designbest-esw/ /usr/src/wordpress/wp-content/plugins/designbest-esw/ | |||
COPY --chown=www-data:www-data ./designbest-esw-lead/ /usr/src/wordpress/wp-content/plugins/designbest-esw-lead/ | |||
</syntaxhighlight> | |||
Nella root dev'essere presente il file <code>xdebug.ini</code> così configurato: | |||
<syntaxhighlight lang="bash"> | |||
zend_extension=xdebug.so | |||
[xdebug] | |||
xdebug.mode=develop,debug | |||
xdebug.discover_client_host = true | |||
xdebug.start_with_request=yes | |||
</syntaxhighlight> | |||
Ecco il '''devcontainer.json''' | |||
<syntaxhighlight lang="json"> | |||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: | |||
// https://github.com/microsoft/vscode-dev-containers/tree/v0.238.0/containers/docker-existing-docker-compose | |||
// If you want to run as a non-root user in the container, see .devcontainer/docker-compose.yml. | |||
{ | |||
"name": "Designbest Commerce ESW", | |||
// Update the 'dockerComposeFile' list if you have more compose files or use different names. | |||
// The .devcontainer/docker-compose.yml file contains any overrides you need/want to make. | |||
"dockerComposeFile": [ | |||
"../docker-compose.yml" | |||
], | |||
// The 'service' property is the name of the service for the container that VS Code should | |||
// use. Update this value and .devcontainer/docker-compose.yml to the real service name. | |||
"service": "wordpress", | |||
// The optional 'workspaceFolder' property is the path VS Code should open by default when | |||
// connected. This is typically a file mount in .devcontainer/docker-compose.yml | |||
"workspaceFolder": "/var/www/html", | |||
"customizations": { | |||
"vscode": { | |||
"extensions": [ | |||
"xdebug.php-pack", "xdebug.php-debug", "bmewburn.vscode-intelephense-client","neilbrayfield.php-docblocker","olback.es6-css-minify" | |||
] | |||
} | |||
}, | |||
// Add the IDs of extensions you want installed when the container is created. | |||
// Use 'forwardPorts' to make a list of ports inside the container available locally. | |||
"forwardPorts": [8000] | |||
} | |||
</syntaxhighlight> | |||
=== Visual Studio === | |||
- Cliccare sul pulsante '''Run & Debug''' e farsi creare in automatico il file <code>.vscode/launch.json</code> per abilitare xdebug per PHP.<br/> | |||
- Creare un file <code>.vscode/settings.json</code> per configurare le estensioni col seguente codice | |||
<syntaxhighlight lang="json"> | |||
{ | |||
"es6-css-minify.minifyOnSave": "exists", | |||
"intelephense.environment.phpVersion": "7.4.3" | |||
} | |||
</syntaxhighlight> | |||
- Aprire <code>wp-config.php</code> e aggiungere appena sotto a <code>define( 'WP_DEBUG',...</code> la riga | |||
<syntaxhighlight lang="bash">define( 'WP_DEBUG_LOG', true );</syntaxhighlight> | |||
=== Wordpress Admin === | |||
Da <code>http://localhost:8000/wp-admin</code><br/> | |||
ho creato credenziali con la mia solita password, utente la mail di lavoro. | |||
* Aggiornare l'aggiornabile | |||
* Installare il plugin '''WooCommerce''' | |||
* ''(opzionale)'' Installare il tema '''Astra''' | |||
** ''Aspetto'' => ''Opzioni Astra'' => spalla dx => ''Installa Plugin Importatore'' | |||
** Da questa pagina installare il template (scegliendo ''Elementor'') '''Custom Printing''' con tutti i suoi contenuti | |||
* ''(opzionale)'' Installare il plugin '''Classic Widget''' | |||
* <del>Installare il plugin '''Checkout Field Editor for WooCommerce'''.</del><br/> <del>Entrare nelle impostazioni e aggiungere i campi ''partita iva'' e ''codice fiscale'' con i nomi <code>billing_cf</code> e <code>billing_piva</code></del> | |||
* ''(developer)'' Installare il plugin '''WP Crontrol''' per vedere la situazione dei ''cron jobs'' e poterli eliminare | |||
* ''(developer)'' Installare il plugin '''WP Hooks Finder''' (by Muhammad Rehman) per poter vedere tutti gli hook in pagina. | |||
== Easy Store - Le specifiche == | |||
Ci saranno '''3 tipi di utenza''' | |||
* Clienti con '''Easy Store''' | |||
* Clienti con '''Outlet''' | |||
* Clienti con '''Easy Store + Outlet''' | |||
Il plugin è in grado di distinguere in quale caso ci troviamo in base al file di configurazione<br/> | |||
<code>/designbest-esw/config/config.php</code><br/> | |||
Dalla voce | |||
<syntaxhighlight lang="php"> | |||
"sorgente-dati" => "designbest", // valori esw o designbest o designbest-esw | |||
</syntaxhighlight> | |||
Il plugin è basato su 5 interfacce ''services'' che cambiano le loro funzioni a seconda del tipo di utenza: | |||
* '''<code>IApiConnectService</code>''' connessione alle API | |||
* '''<code>IProductsService</code>''' sincronizzazione prodotti | |||
* '''<code>IOrdersService</code>''' gestione degli ordini (fattura ecc) | |||
* '''<code>IAdminService</code>''' gestione backoffice WP | |||
* '''<code>ICronJobsService</code>''' gestione di cron-job per sincronizzare | |||
<br/> | |||
=== Clienti con Easy Store === | |||
File <code>config.php</code> correttamente configurato per questa utenza: | |||
<syntaxhighlight lang="php"> | |||
return array( | |||
"environment" => "test", // "production" | |||
"sorgente-dati" => "esw", // valori esw o designbest o designbest-esw | |||
"esw_api-domain" => "https://easyapi6.eswportal.it", | |||
"esw_negoziocode" => "Attivo 2", | |||
"esw-x-apikey" => "j9MDojFf4EmbznjJvimErUJ4YWJHWlY4N1VTTWYwM2NRZUZOSmc=", | |||
"esw-dbconnection" => "291_EMMERRE_TEST", | |||
"esw-codicemagazzino" => ["MAG_10","MAG_11","MAG_23"], // magazzini accettati dall'import | |||
"esw-codicevenditore" => "ONL49554", | |||
"esw-incassi-codice_causale" => "05SLD", | |||
"esw-servizi-codice" => "SE", | |||
"esw-mapping-pagamenti" => ["bacs" => "BON","xpay"=> "CC"], | |||
// Gestione clienti che hanno i campi cf, piva e sdi creati con altri plugin | |||
"esw-customer-ordermetadata" => [ | |||
"create" => true, // se true crea i campi customCheckoutFields e li mostra in backoffice (false se lo fa già un plugin) | |||
"cf" => "_billing_cf", | |||
"piva" => "_billing_piva", | |||
"sdi" => "_billing_sdi" | |||
] | |||
); | |||
</syntaxhighlight> | </syntaxhighlight> | ||
Le API di Easy Store non permettono di caricare articoli sul gestionale, ma solo di leggerli.<br/> | |||
Per ''tenere sincronizzati'' i prodotti è necessario montare un pooling tramite un ''cron-job'' che andrà a leggere i dati del gestionale e li proietterà sul commerce.<br/> | |||
Aggiunta funzione per caricare un elenco pre-compilato di categorie in quanto EasyStore non le considera.<br/> | |||
Nelle chiamate, tutti i valori booleani vanno passati come stringa utilizzando ''"true"'' o ''"false"''.<br/><br/> | |||
'''<code>IApiConnectService</code>''' permette la connessione alle API di Easy Store<br/> | |||
:https://easyapitest.eswportal.it/developer/index<br/><br/> | |||
'''<code>IProductsService</code>''' mette a disposizione | |||
:* <code>createBrandTaxonomy()</code> che si occupa di aggiungere la tassonomia del ''manufacturer'' che stranamente in WooCommerce non è presente.<br/> | |||
:<del>Oltre a questo inserisce un elenco convenzionato di ''categories'' perché Easy Store non ha i dati sulle categorie/tipologie di prodotto.</del> | |||
:* <code>allProductsSync()</code> Legge tutti i prodotti del negozio specificato in <code>config.php</code> che hanno il flag ''commerce'' e li sincronizza con WooCommerce.<br/> | |||
:Se sono già presenti si limita ad aggiornare solo i campi ''prezzo'' e ''giacenza''. Altrimenti inserisce l'intero prodotto.<br/> | |||
:I dati sincronizzati non hanno dati sufficienti per una pubblicazione (mancano titolo, descrizione e immagini) e saranno importati come ''bozze''. | |||
:* <code>insertDefaultCategories()</code> Inserisce gli ambienti default per definire una lista di partenza. | |||
: Il pulsante si trova nell'admin | |||
<br/><br/> | |||
'''<code>IOrdersService</code>''' gestisce l'acquisto sincronizzando tutto col gestionale. | |||
:* <code>customCheckoutFields()</code> Aggiunge ''codice fiscale'' e ''partita I.V.A.'' ai campi di checkout del carrello. | |||
:* <code>newOrder()</code> spedisce a Easy Store tutte le informazioni sull'acquisto. | |||
: Si occupa di registrare l'anagrafica e il prodotto venduto tramite i corrispondenti endpoint post <code>anagrafica</code> e post <code>vendite</code>.<br/> | |||
:In queste chiamate alcuni parametri sono costanti definite durante la progettazione. | |||
::* <code>codice_venditore = ONL49554</code> | |||
::* <code>tipo_fattura = FT</code> | |||
::* <code>codice_fornitore</code> viene passato se è definito, in caso contrario passa <code>ECOMMERCE</code> | |||
::* <code>codice_magazzino = MAG</code> ora proviene dalla configurazione | |||
::* <code>prezzo_forzato = True</code> utilizzare i valori string ''"True"'' o ''"False"'' per i booleani | |||
<br/><br/> | |||
'''<code>IAdminService</code>''' gestisce le pagine di backoffice e le loro logiche lato server.<br/> | |||
:Piazza l'elemento nel menu con l'icona adeguata, mette a disposizione una pagina che riassume le caratteristiche del plugin e permette una sincronizzazione manuale premendo un pulsante.<br/><br/> | |||
'''<code>ICronJobsService</code>''' Attiva (e predispone la disattivazione) di un ''cron job'' che chiama la sincronizzazione dei prodotti ( <code>IProductsService::allProductsSync()</code> ) tutti i giorni a partire dalle 8 per 2 volte al giorno.<br/><br/> | |||
=== Clienti con outlet === | |||
File <code>config.php</code> correttamente configurato per questa utenza: | |||
<syntaxhighlight lang="php"> | |||
return array( | |||
"sorgente-dati" => "designbest", | |||
"environment" => "test", // "production", | |||
"db-api-domain" => "https://apicore.dbdemo47.com", | |||
"db-token_endpoint" => "/token", | |||
"db-token_username" => "designbestrest", | |||
"db-token_password" => "Z3+3MlGwEbz#", | |||
"db-shopnetid" => 318182 // Bensa Arredamenti | |||
); | |||
</syntaxhighlight> | |||
Il database di Designbest ha dei dati più completi rispetto a ESW per un e-commerce.<br/> | |||
Allo stesso modo, il meccanismo di sincronizzazione porterà i dati dal database di Designbest a quello del commerce locale.<br/><br/> | |||
'''<code>IApiConnectService</code>''' permette la connessione alle API di Designbest<br/> | |||
:https://ws.designbest.com/doc/index<br/><br/> | |||
'''<code>IProductsService</code>''' mette a disposizione | |||
:* <code>createBrandTaxonomy()</code> che si occupa di aggiungere la tassonomia del ''manufacturer'' che stranamente in WooCommerce non è presente.<br/> | |||
:Non si occupa di aggiungere ''categories'' al pool di base perché i prodotti Designbest forniscono la precisa tipologia. | |||
:* <code>allProductsSync()</code> Legge tutti i prodotti del negozio specificato in <code>config.php</code> che hanno il flag ''e-commerce approved'' e li sincronizza con WooCommerce.<br/> | |||
:Se sono già presenti si limita ad aggiornare solo i campi ''prezzo'' e ''giacenza''. Altrimenti inserisce l'intero prodotto.<br/> | |||
:I dati sincronizzati saranno importati come ''bozze''.<br/><br/> | |||
'''<code>IOrdersService</code>''' gestisce l'acquisto sincronizzando tutto col gestionale. | |||
:* <code>customCheckoutFields()</code> Aggiunge ''codice fiscale'' e ''partita I.V.A.'' ai campi di checkout del carrello. | |||
:* <code>newOrder()</code> comunica a Designbest la diminuzione della giacenza dell'articolo (non implementato in quanto sovrascritto dalla sincronizzazione programmata).<br/> | |||
<br/> | |||
'''<code>IAdminService</code>''' gestisce le pagine di backoffice e le loro logiche lato server.<br/> | |||
:Piazza l'elemento nel menu con l'icona adeguata, mette a disposizione una pagina che riassume le caratteristiche del plugin e permette una sincronizzazione manuale premendo un pulsante.<br/><br/> | |||
'''<code>ICronJobsService</code>''' Attiva (e predispone la disattivazione) di un ''cron job'' che chiama la sincronizzazione dei prodotti ( <code>IProductsService::allProductsSync()</code> ) tutti i giorni a partire dalle 8 per 2 volte al giorno.<br/><br/> | |||
=== Clienti con Outlet + Easy Store === | |||
File <code>config.php</code> correttamente configurato per questa utenza: | |||
<syntaxhighlight lang="php"> | |||
return array( | |||
"sorgente-dati" => "designbest-esw", | |||
"environment" => "test", // "production" | |||
// Configurazione esw | |||
"esw_negoziocode" => "01", // Arredamenti Casabella su Esw | |||
"esw-x-apikey" => "hEckyjWBYUycOIRiUZUgJUJ4YWJHWlY4N1VTTWYwM2NRZUZOSmc=", | |||
"esw-dbconnection" => "173_WMECOMMERCE", | |||
// Configurazione designbest | |||
"db-token_endpoint" => "https://ws.designbest.com/token", | |||
"db-token_username" => "designbestrest", | |||
"db-token_password" => "Z3+3MlGwEbz#", | |||
"db-shop_piva" => "00258570274" // Arredamenti Casabella su Outlet | |||
); | |||
</syntaxhighlight> | |||
I ''services'' dovranno comportarsi in parte come Esw e in parte come Outlet.<br/> | |||
Importante che nella configurazione si specifichi la stessa entità con i 2 diversi identificativi (es. Casabella Arredamenti su ESW e lo stesso su Outlet). | |||
=== Clienti con sviluppi custom non scalabili === | |||
Per rispondere alle richieste non scalabili degli utenti sono stati inseriti degli '''hook''' nei punti cardine del plugin. | |||
Al momento sono i seguenti: | |||
* <code>dbesw_eswinsertanagrafica</code> => <code>($anag, $order)</code> ''[filter]'' | |||
* <code>dbesw_eswinsertvendita</code> => <code>($vendita, $order)</code> ''[filter]'' | |||
==== Utilizzo ==== | |||
È necessario creare un '''nuovo file .php''', ad esempio '''NomeClienteCustomHooks.php''', che conterrà le personalizzazioni degli hook nella cartella <code>/config/CustomHooks/</code>. | |||
Per utilizzarlo è necessario dichiararlo nel file <code>/config/config.php</code> sotto alla voce '''custom-hooks'' | |||
<syntaxhighlight lang="php"> | |||
<?php | |||
defined( 'ABSPATH' ) || exit; | |||
return array( | |||
// ... altre conf | |||
"custom-hooks" => "NomeClienteCustomHooks.php" | |||
); | |||
</syntaxhighlight> | |||
e il file, che verra eseguito durante l'inizializzazione del plugin, potrà avere i seguenti contenuti: | |||
<syntaxhighlight lang="php"> | |||
<?php | |||
// SVILUPPI CUSTOM per DTime | |||
defined( 'ABSPATH' ) || exit; | |||
add_filter("dbesw_eswinsertanagrafica", function($anag, $order) { | |||
// Manipolazione custom di $anag utilizzando $order per recuperare dati | |||
return $anag; | |||
}, 10, 2); | |||
add_filter("dbesw_eswinsertvendita", function($vendita, $order) { | |||
// Manipolazione custom di $vendita utilizzando $order per recuperare dati | |||
return $vendita; | |||
}, 10, 2); | |||
</syntaxhighlight> | |||
== Attivazione plugin == | |||
Qui i passaggi per attivare il plugin sul sito wordpress del cliente.<br/> | |||
'''IMPORTANTE'''<br/> | |||
Nell'ambiente di ''test'', nel file <code>wp-config.php</code> inserire la costante | |||
<syntaxhighlight lang="php"> | |||
define( 'WP_DEBUG', true ); | |||
define( 'WP_DEBUG_LOG', true ); | |||
define( 'WP_DEBUG_DISPLAY', true ); | |||
define( 'WP_ENVIRONMENT_TYPE', 'staging' ); // mettere 'local' per sviluppo locale | |||
</syntaxhighlight> | |||
In ''produzione'' rimuovere <code>WP_ENVIRONMENT_TYPE</code> e rimuovere WP_DEBUG e figli. | |||
Innanzitutto bisogna recuperare dal '''cliente''' | |||
* Credenziali per accedere a <code>wp-admin</code> | |||
* Credenziali per accedere a <code>FTP</code> | |||
Poi bisogna farsi dare da '''Sintesys''' | |||
* <code>api-endpoint</code> | |||
* <code>negozio_code</code> | |||
* <code>x-apikey</code> | |||
* <code>dbconnection</code> | |||
* <code>codice_magazzino</code><br/> | |||
Una volta che si hanno tutti i dati. | |||
* Installare (se non presente) il plugin dipendenza '''WooCommerce''' | |||
* Copiare su FTP il folder del plugin nella cartella <code>/wp-content/plugins</code> | |||
* Attivare il plugin tramite l'apposita sezione della dashboard | |||
* (opzionale) installare il plugin '''WP Crontrol''' per vedere i cron-job sotto il menu Strumenti | |||
== ⚠ Stranezze tecniche ⚠ == | |||
Questa sezione raccoglie tutti i tipi di eccezione che abbiamo incontrato durante lo sviluppo. | |||
=== WooCommerce incompatibilità di configurazione === | |||
Fonte:<br/> | |||
https://rudrastyh.com/woocommerce/high-performance-order-storage.html<br/> | |||
Esiste una modalità di WooCommerce che si chiama '''HPOS''', si basa sull'utilizzo di tabelle proprie ottimizzate invece di quelle del core WP.<br/> | |||
Si attiva da <code>WooCommerce => Impostazioni => Avanzate => Funzioni/Features</code>, non si lascia attivare se qualche plugin non è compatibile.<br/> | |||
Ci sono diversi casi da gestire | |||
* Il caso particolare dell'hook <code>shop_order</code> che cambia nome in <code>woocommerce_page_wc-orders</code>. | |||
* L'impossibilità di usare <code>get_post_meta()</code> quando è attivo. | |||
Nel primo caso è possibile scrivere un codice che è compatibile sia che HPOS sia abilitato che non: | |||
<syntaxhighlight lang="php"> | |||
public function esw_order_json_data() : void { | |||
add_meta_box( | |||
'esw-order-json-data', | |||
'EASY STORE ORDER DATA', | |||
[$this,'esw_render_meta_box'], | |||
wc_get_page_screen_id( 'shop-order' ), // woocommerce_page_wc-orders (oppure shop_order)is the post type of the admin order page | |||
'normal', // change to 'side' to move box to side column | |||
'low' // priority (where on page to put the box) | |||
); | |||
} | |||
public function esw_render_meta_box($post,$metabox) : void { | |||
//https://rudrastyh.com/woocommerce/high-performance-order-storage.html#screen_id-changes | |||
//Se opzione di Woocommerce HPOS è attiva la variabile $post è di tipo WC_Order e non può accedere direttamente all'ID | |||
$order_id = ( $post instanceof \WP_Post ) | |||
? $post->ID | |||
: $post->get_id(); | |||
$json_data = $this->eswdb_service->getOrder($order_id); | |||
if($json_data != null){ | |||
echo '<pre>'.$json_data. '</pre>'; | |||
}else{ | |||
echo '<p>Ordine non gestito da Easy Store</p>'; | |||
} | |||
// Metabox content | |||
} | |||
</syntaxhighlight> | |||
=== Hook non affidabili === | |||
L'hook <code>woocommerce_checkout_order_processed</code> non funziona su alcune installazioni, non riusciamo a capire quale sia il fattore che interviene. | |||
Usare <code>woocommerce_thankyou</code> piuttosto. | |||
== Clienti che usano questo plugin == | |||
Per il momento sono | |||
* [https://www.emmerrearredamenti.com/ EmmeErre] | |||
* [https://www.dtimeshop.com/ DTime] | |||
* [https://arredly.it/arredomobilioutlet/ Arredo Mobili Outlet] | |||
== WooCommerce Pagamenti == | |||
* WooCommerce PayPal Payments | |||
* WooCommerce Stripe Gateway | |||
=== PayPal Sandbox === | |||
Vedere credenziali usate per commerce http://wiki.wmdemo.it/index.php?title=PayPal_Sandbox | |||
Versione attuale delle 09:13, 6 nov 2024
Il progetto prevede la creazione di un mini-sito con commerce integrato con Easy Store Web.
Ambiente di lavoro
[modifica]Container
[modifica]Abbiamo optato per un docker container così strutturato
docker-compose.yml
version: '3.9'
services:
db:
image: mysql:8.3
ports:
- 3306:3306
environment:
MYSQL_DATABASE: webmobili
MYSQL_USER: webmobili
MYSQL_PASSWORD: w3bm0b1l1
MYSQL_ROOT_PASSWORD: w3bm0b1l1
volumes:
- db:/var/lib/mysql
wordpress:
depends_on:
- db
build:
context: ./
ports:
- 8000:80
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: webmobili
WORDPRESS_DB_PASSWORD: w3bm0b1l1
WORDPRESS_DB_NAME: webmobili
WORDPRESS_DEBUG: 1
TZ: "Europe/Rome"
volumes:
- wordpress:/var/www/html
volumes:
db:
wordpress:
Punta al seguente Dockerfile che si occupa di configurare xdebug per PHP.
FROM wordpress:6.6.2-apache
RUN apt-get update && \
pecl install xdebug \
&& docker-php-ext-enable xdebug
# Copy xdebug.ini to /usr/local/etc/php/conf.d/
COPY ./*.ini /usr/local/etc/php/conf.d/
# Copy plugin data to to /usr/src/wordpress/wp-content/plugins/
COPY --chown=www-data:www-data ./designbest-esw/ /usr/src/wordpress/wp-content/plugins/designbest-esw/
COPY --chown=www-data:www-data ./designbest-esw-lead/ /usr/src/wordpress/wp-content/plugins/designbest-esw-lead/
Nella root dev'essere presente il file xdebug.ini così configurato:
zend_extension=xdebug.so
[xdebug]
xdebug.mode=develop,debug
xdebug.discover_client_host = true
xdebug.start_with_request=yes
Ecco il devcontainer.json
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.238.0/containers/docker-existing-docker-compose
// If you want to run as a non-root user in the container, see .devcontainer/docker-compose.yml.
{
"name": "Designbest Commerce ESW",
// Update the 'dockerComposeFile' list if you have more compose files or use different names.
// The .devcontainer/docker-compose.yml file contains any overrides you need/want to make.
"dockerComposeFile": [
"../docker-compose.yml"
],
// The 'service' property is the name of the service for the container that VS Code should
// use. Update this value and .devcontainer/docker-compose.yml to the real service name.
"service": "wordpress",
// The optional 'workspaceFolder' property is the path VS Code should open by default when
// connected. This is typically a file mount in .devcontainer/docker-compose.yml
"workspaceFolder": "/var/www/html",
"customizations": {
"vscode": {
"extensions": [
"xdebug.php-pack", "xdebug.php-debug", "bmewburn.vscode-intelephense-client","neilbrayfield.php-docblocker","olback.es6-css-minify"
]
}
},
// Add the IDs of extensions you want installed when the container is created.
// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [8000]
}
Visual Studio
[modifica]- Cliccare sul pulsante Run & Debug e farsi creare in automatico il file .vscode/launch.json per abilitare xdebug per PHP.
- Creare un file .vscode/settings.json per configurare le estensioni col seguente codice
{
"es6-css-minify.minifyOnSave": "exists",
"intelephense.environment.phpVersion": "7.4.3"
}
- Aprire wp-config.php e aggiungere appena sotto a define( 'WP_DEBUG',... la riga
define( 'WP_DEBUG_LOG', true );
Wordpress Admin
[modifica]Da http://localhost:8000/wp-admin
ho creato credenziali con la mia solita password, utente la mail di lavoro.
- Aggiornare l'aggiornabile
- Installare il plugin WooCommerce
- (opzionale) Installare il tema Astra
- Aspetto => Opzioni Astra => spalla dx => Installa Plugin Importatore
- Da questa pagina installare il template (scegliendo Elementor) Custom Printing con tutti i suoi contenuti
- (opzionale) Installare il plugin Classic Widget
Installare il plugin Checkout Field Editor for WooCommerce.
Entrare nelle impostazioni e aggiungere i campi partita iva e codice fiscale con i nomibilling_cfebilling_piva- (developer) Installare il plugin WP Crontrol per vedere la situazione dei cron jobs e poterli eliminare
- (developer) Installare il plugin WP Hooks Finder (by Muhammad Rehman) per poter vedere tutti gli hook in pagina.
Easy Store - Le specifiche
[modifica]Ci saranno 3 tipi di utenza
- Clienti con Easy Store
- Clienti con Outlet
- Clienti con Easy Store + Outlet
Il plugin è in grado di distinguere in quale caso ci troviamo in base al file di configurazione
/designbest-esw/config/config.php
Dalla voce
"sorgente-dati" => "designbest", // valori esw o designbest o designbest-esw
Il plugin è basato su 5 interfacce services che cambiano le loro funzioni a seconda del tipo di utenza:
IApiConnectServiceconnessione alle APIIProductsServicesincronizzazione prodottiIOrdersServicegestione degli ordini (fattura ecc)IAdminServicegestione backoffice WPICronJobsServicegestione di cron-job per sincronizzare
Clienti con Easy Store
[modifica]File config.php correttamente configurato per questa utenza:
return array(
"environment" => "test", // "production"
"sorgente-dati" => "esw", // valori esw o designbest o designbest-esw
"esw_api-domain" => "https://easyapi6.eswportal.it",
"esw_negoziocode" => "Attivo 2",
"esw-x-apikey" => "j9MDojFf4EmbznjJvimErUJ4YWJHWlY4N1VTTWYwM2NRZUZOSmc=",
"esw-dbconnection" => "291_EMMERRE_TEST",
"esw-codicemagazzino" => ["MAG_10","MAG_11","MAG_23"], // magazzini accettati dall'import
"esw-codicevenditore" => "ONL49554",
"esw-incassi-codice_causale" => "05SLD",
"esw-servizi-codice" => "SE",
"esw-mapping-pagamenti" => ["bacs" => "BON","xpay"=> "CC"],
// Gestione clienti che hanno i campi cf, piva e sdi creati con altri plugin
"esw-customer-ordermetadata" => [
"create" => true, // se true crea i campi customCheckoutFields e li mostra in backoffice (false se lo fa già un plugin)
"cf" => "_billing_cf",
"piva" => "_billing_piva",
"sdi" => "_billing_sdi"
]
);
Le API di Easy Store non permettono di caricare articoli sul gestionale, ma solo di leggerli.
Per tenere sincronizzati i prodotti è necessario montare un pooling tramite un cron-job che andrà a leggere i dati del gestionale e li proietterà sul commerce.
Aggiunta funzione per caricare un elenco pre-compilato di categorie in quanto EasyStore non le considera.
Nelle chiamate, tutti i valori booleani vanno passati come stringa utilizzando "true" o "false".
IApiConnectService permette la connessione alle API di Easy Store
IProductsService mette a disposizione
createBrandTaxonomy()che si occupa di aggiungere la tassonomia del manufacturer che stranamente in WooCommerce non è presente.
Oltre a questo inserisce un elenco convenzionato di categories perché Easy Store non ha i dati sulle categorie/tipologie di prodotto.allProductsSync()Legge tutti i prodotti del negozio specificato inconfig.phpche hanno il flag commerce e li sincronizza con WooCommerce.
- Se sono già presenti si limita ad aggiornare solo i campi prezzo e giacenza. Altrimenti inserisce l'intero prodotto.
- I dati sincronizzati non hanno dati sufficienti per una pubblicazione (mancano titolo, descrizione e immagini) e saranno importati come bozze.
insertDefaultCategories()Inserisce gli ambienti default per definire una lista di partenza.
- Il pulsante si trova nell'admin
IOrdersService gestisce l'acquisto sincronizzando tutto col gestionale.
customCheckoutFields()Aggiunge codice fiscale e partita I.V.A. ai campi di checkout del carrello.newOrder()spedisce a Easy Store tutte le informazioni sull'acquisto.
- Si occupa di registrare l'anagrafica e il prodotto venduto tramite i corrispondenti endpoint post
anagraficae postvendite. - In queste chiamate alcuni parametri sono costanti definite durante la progettazione.
codice_venditore = ONL49554tipo_fattura = FTcodice_fornitoreviene passato se è definito, in caso contrario passaECOMMERCEcodice_magazzino = MAGora proviene dalla configurazioneprezzo_forzato = Trueutilizzare i valori string "True" o "False" per i booleani
IAdminService gestisce le pagine di backoffice e le loro logiche lato server.
- Piazza l'elemento nel menu con l'icona adeguata, mette a disposizione una pagina che riassume le caratteristiche del plugin e permette una sincronizzazione manuale premendo un pulsante.
ICronJobsService Attiva (e predispone la disattivazione) di un cron job che chiama la sincronizzazione dei prodotti ( IProductsService::allProductsSync() ) tutti i giorni a partire dalle 8 per 2 volte al giorno.
Clienti con outlet
[modifica]File config.php correttamente configurato per questa utenza:
return array(
"sorgente-dati" => "designbest",
"environment" => "test", // "production",
"db-api-domain" => "https://apicore.dbdemo47.com",
"db-token_endpoint" => "/token",
"db-token_username" => "designbestrest",
"db-token_password" => "Z3+3MlGwEbz#",
"db-shopnetid" => 318182 // Bensa Arredamenti
);
Il database di Designbest ha dei dati più completi rispetto a ESW per un e-commerce.
Allo stesso modo, il meccanismo di sincronizzazione porterà i dati dal database di Designbest a quello del commerce locale.
IApiConnectService permette la connessione alle API di Designbest
IProductsService mette a disposizione
createBrandTaxonomy()che si occupa di aggiungere la tassonomia del manufacturer che stranamente in WooCommerce non è presente.
- Non si occupa di aggiungere categories al pool di base perché i prodotti Designbest forniscono la precisa tipologia.
allProductsSync()Legge tutti i prodotti del negozio specificato inconfig.phpche hanno il flag e-commerce approved e li sincronizza con WooCommerce.
- Se sono già presenti si limita ad aggiornare solo i campi prezzo e giacenza. Altrimenti inserisce l'intero prodotto.
- I dati sincronizzati saranno importati come bozze.
IOrdersService gestisce l'acquisto sincronizzando tutto col gestionale.
customCheckoutFields()Aggiunge codice fiscale e partita I.V.A. ai campi di checkout del carrello.newOrder()comunica a Designbest la diminuzione della giacenza dell'articolo (non implementato in quanto sovrascritto dalla sincronizzazione programmata).
IAdminService gestisce le pagine di backoffice e le loro logiche lato server.
- Piazza l'elemento nel menu con l'icona adeguata, mette a disposizione una pagina che riassume le caratteristiche del plugin e permette una sincronizzazione manuale premendo un pulsante.
ICronJobsService Attiva (e predispone la disattivazione) di un cron job che chiama la sincronizzazione dei prodotti ( IProductsService::allProductsSync() ) tutti i giorni a partire dalle 8 per 2 volte al giorno.
Clienti con Outlet + Easy Store
[modifica]File config.php correttamente configurato per questa utenza:
return array(
"sorgente-dati" => "designbest-esw",
"environment" => "test", // "production"
// Configurazione esw
"esw_negoziocode" => "01", // Arredamenti Casabella su Esw
"esw-x-apikey" => "hEckyjWBYUycOIRiUZUgJUJ4YWJHWlY4N1VTTWYwM2NRZUZOSmc=",
"esw-dbconnection" => "173_WMECOMMERCE",
// Configurazione designbest
"db-token_endpoint" => "https://ws.designbest.com/token",
"db-token_username" => "designbestrest",
"db-token_password" => "Z3+3MlGwEbz#",
"db-shop_piva" => "00258570274" // Arredamenti Casabella su Outlet
);
I services dovranno comportarsi in parte come Esw e in parte come Outlet.
Importante che nella configurazione si specifichi la stessa entità con i 2 diversi identificativi (es. Casabella Arredamenti su ESW e lo stesso su Outlet).
Clienti con sviluppi custom non scalabili
[modifica]Per rispondere alle richieste non scalabili degli utenti sono stati inseriti degli hook nei punti cardine del plugin.
Al momento sono i seguenti:
dbesw_eswinsertanagrafica=>($anag, $order)[filter]dbesw_eswinsertvendita=>($vendita, $order)[filter]
Utilizzo
[modifica]È necessario creare un nuovo file .php, ad esempio NomeClienteCustomHooks.php, che conterrà le personalizzazioni degli hook nella cartella /config/CustomHooks/.
Per utilizzarlo è necessario dichiararlo nel file /config/config.php sotto alla voce 'custom-hooks
<?php
defined( 'ABSPATH' ) || exit;
return array(
// ... altre conf
"custom-hooks" => "NomeClienteCustomHooks.php"
);
e il file, che verra eseguito durante l'inizializzazione del plugin, potrà avere i seguenti contenuti:
<?php
// SVILUPPI CUSTOM per DTime
defined( 'ABSPATH' ) || exit;
add_filter("dbesw_eswinsertanagrafica", function($anag, $order) {
// Manipolazione custom di $anag utilizzando $order per recuperare dati
return $anag;
}, 10, 2);
add_filter("dbesw_eswinsertvendita", function($vendita, $order) {
// Manipolazione custom di $vendita utilizzando $order per recuperare dati
return $vendita;
}, 10, 2);
Attivazione plugin
[modifica]Qui i passaggi per attivare il plugin sul sito wordpress del cliente.
IMPORTANTE
Nell'ambiente di test, nel file wp-config.php inserire la costante
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', true );
define( 'WP_ENVIRONMENT_TYPE', 'staging' ); // mettere 'local' per sviluppo locale
In produzione rimuovere WP_ENVIRONMENT_TYPE e rimuovere WP_DEBUG e figli.
Innanzitutto bisogna recuperare dal cliente
- Credenziali per accedere a
wp-admin - Credenziali per accedere a
FTP
Poi bisogna farsi dare da Sintesys
api-endpointnegozio_codex-apikeydbconnectioncodice_magazzino
Una volta che si hanno tutti i dati.
- Installare (se non presente) il plugin dipendenza WooCommerce
- Copiare su FTP il folder del plugin nella cartella
/wp-content/plugins - Attivare il plugin tramite l'apposita sezione della dashboard
- (opzionale) installare il plugin WP Crontrol per vedere i cron-job sotto il menu Strumenti
⚠ Stranezze tecniche ⚠
[modifica]Questa sezione raccoglie tutti i tipi di eccezione che abbiamo incontrato durante lo sviluppo.
WooCommerce incompatibilità di configurazione
[modifica]Fonte:
https://rudrastyh.com/woocommerce/high-performance-order-storage.html
Esiste una modalità di WooCommerce che si chiama HPOS, si basa sull'utilizzo di tabelle proprie ottimizzate invece di quelle del core WP.
Si attiva da WooCommerce => Impostazioni => Avanzate => Funzioni/Features, non si lascia attivare se qualche plugin non è compatibile.
Ci sono diversi casi da gestire
- Il caso particolare dell'hook
shop_orderche cambia nome inwoocommerce_page_wc-orders. - L'impossibilità di usare
get_post_meta()quando è attivo.
Nel primo caso è possibile scrivere un codice che è compatibile sia che HPOS sia abilitato che non:
public function esw_order_json_data() : void {
add_meta_box(
'esw-order-json-data',
'EASY STORE ORDER DATA',
[$this,'esw_render_meta_box'],
wc_get_page_screen_id( 'shop-order' ), // woocommerce_page_wc-orders (oppure shop_order)is the post type of the admin order page
'normal', // change to 'side' to move box to side column
'low' // priority (where on page to put the box)
);
}
public function esw_render_meta_box($post,$metabox) : void {
//https://rudrastyh.com/woocommerce/high-performance-order-storage.html#screen_id-changes
//Se opzione di Woocommerce HPOS è attiva la variabile $post è di tipo WC_Order e non può accedere direttamente all'ID
$order_id = ( $post instanceof \WP_Post )
? $post->ID
: $post->get_id();
$json_data = $this->eswdb_service->getOrder($order_id);
if($json_data != null){
echo '<pre>'.$json_data. '</pre>';
}else{
echo '<p>Ordine non gestito da Easy Store</p>';
}
// Metabox content
}
Hook non affidabili
[modifica]L'hook woocommerce_checkout_order_processed non funziona su alcune installazioni, non riusciamo a capire quale sia il fattore che interviene.
Usare woocommerce_thankyou piuttosto.
Clienti che usano questo plugin
[modifica]Per il momento sono
WooCommerce Pagamenti
[modifica]- WooCommerce PayPal Payments
- WooCommerce Stripe Gateway
PayPal Sandbox
[modifica]Vedere credenziali usate per commerce http://wiki.wmdemo.it/index.php?title=PayPal_Sandbox