Compare commits

..

2 Commits

Author SHA1 Message Date
Jorge Penadés 17243878f9 Merge branch 'dev' into 6492-replaceProcedure
gitea/hedera-web/pipeline/pr-dev This commit looks good Details
2024-04-10 10:36:06 +00:00
Jorge Penadés 59ea7b335b feat: refs #6492 replace procedure
gitea/hedera-web/pipeline/pr-dev This commit looks good Details
2024-04-10 12:29:28 +02:00
26 changed files with 235 additions and 85 deletions

1
.gitignore vendored
View File

@ -1,6 +1,5 @@
node_modules
build/
dist/
config.my.php
.vscode/
.quasar

View File

@ -28,7 +28,7 @@ RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
# Hedera
RUN curl -sL https://apt.verdnatura.es/conf/verdnatura.gpg | tee /etc/apt/trusted.gpg.d/verdnatura.gpg \
RUN curl -sL https://apt.verdnatura.es/conf/verdnatura.gpg | apt-key add - \
&& echo "deb http://apt.verdnatura.es/ bookworm main" \
> /etc/apt/sources.list.d/vn.list \
&& apt-get update \

73
Jenkinsfile vendored
View File

@ -4,12 +4,20 @@ def BRANCH_ENV = [
test: 'test',
master: 'production'
]
def remote = [:]
node {
stage('Setup') {
env.MAIN_REPLICAS = 1
env.CRON_REPLICAS = 0
env.NODE_ENV = BRANCH_ENV[env.BRANCH_NAME] ?: 'dev'
switch (env.BRANCH_NAME) {
case 'master':
env.MAIN_REPLICAS = 3
env.CRON_REPLICAS = 1
break
}
echo "NODE_NAME: ${env.NODE_NAME}"
echo "WORKSPACE: ${env.WORKSPACE}"
}
@ -18,6 +26,7 @@ pipeline {
agent any
environment {
PROJECT_NAME = 'hedera-web'
STACK_NAME = "${env.PROJECT_NAME}-${env.BRANCH_NAME}"
}
stages {
stage('Debuild') {
@ -29,28 +38,35 @@ pipeline {
}
agent {
docker {
image 'registry.verdnatura.es/verdnatura/debuild:2.23.4-vn7'
image 'registry.verdnatura.es/debuild:2.23.4-vn1'
registryUrl 'https://registry.verdnatura.es/'
registryCredentialsId 'docker-registry'
args '-v /mnt/appdata/reprepro:/reprepro'
}
}
steps {
sh 'debuild -us -uc -b'
sh 'mkdir -p debuild'
sh 'mv ../hedera-web_* debuild'
sh 'vn-includedeb bookworm'
}
}
stage('Container') {
when {
anyOf {
branch 'master'
branch 'test'
}
}
environment {
CREDS = credentials('docker-registry')
}
steps {
script {
def files = findFiles(glob: 'debuild/*.changes')
files.each { file -> env.CHANGES_FILE = file.name }
}
configFileProvider([
configFile(fileId: "dput.cf", variable: 'DPUT_CONFIG')
]) {
sshagent(credentials: ['jenkins-agent']) {
sh 'dput --config "$DPUT_CONFIG" verdnatura "debuild/$CHANGES_FILE"'
}
def packageJson = readJSON file: 'package.json'
env.VERSION = packageJson.version
}
sh 'docker login --username $CREDS_USR --password $CREDS_PSW $REGISTRY'
sh 'docker-compose build --build-arg BUILD_ID=$BUILD_ID --parallel'
sh 'docker-compose push'
}
}
stage('Deploy') {
@ -61,35 +77,14 @@ pipeline {
}
}
environment {
CREDS = credentials('docker-registry')
IMAGE = "$REGISTRY/verdnatura/hedera-web"
DOCKER_HOST = "${env.SWARM_HOST}"
}
steps {
script {
def packageJson = readJSON file: 'package.json'
env.VERSION = "${packageJson.version}"
env.TAG = "${packageJson.version}-build${env.BUILD_ID}"
}
sh 'docker-compose build --build-arg BUILD_ID=$BUILD_ID --parallel'
sh 'docker login --username $CREDS_USR --password $CREDS_PSW $REGISTRY'
sh 'docker push $IMAGE:$TAG'
script {
if (env.BRANCH_NAME == 'master') {
sh 'docker tag $IMAGE:$TAG $IMAGE:latest'
sh 'docker push $IMAGE:latest'
}
}
withKubeConfig([
serverUrl: "$KUBERNETES_API",
credentialsId: 'kubernetes',
namespace: 'salix'
]) {
sh 'kubectl set image deployment/hedera-web-$BRANCH_NAME hedera-web-$BRANCH_NAME=$IMAGE:$TAG'
sh 'kubectl set image deployment/hedera-web-cron-$BRANCH_NAME hedera-web-cron-$BRANCH_NAME=$IMAGE:$TAG'
env.VERSION = packageJson.version
}
sh "docker stack deploy --with-registry-auth --compose-file docker-compose.yml ${env.STACK_NAME}"
}
}
}

View File

@ -5,12 +5,9 @@ Hedera is the main web shop page for Verdnatura.
## Prerequisites
Required applications.
* PHP >= 8.4
* Node.js >= 20.0
Take a look to *debian/control* file to see additional dependencies.
Copy config.php to *config.my.php* and place your DB config there.
* PHP >= 7.0
* Node.js >= 8.0
* [php-vn-lib](https://gitea.verdnatura.es/verdnatura/php-vn-lib)
### Installing dependencies and launching

View File

@ -24,7 +24,7 @@ return [
,'port' => 3306
,'schema' => 'hedera'
,'user' => 'hedera-web'
,'pass' => '' // base64 encoded
,'pass' => ''
,'tz' => 'Europe/madrid'
]
];

2
debian/changelog vendored
View File

@ -1,4 +1,4 @@
hedera-web (25.4.4) stable; urgency=low
hedera-web (24.8.2) stable; urgency=low
* Initial Release.

1
debian/cron.d vendored
View File

@ -3,6 +3,7 @@ MAILTO=webmaster
*/2 * * * * root hedera-web.php -m edi/load
0 23 * * * root hedera-web.php -m edi/clean
0 5 * * * root hedera-web.php -m edi/update
0 5 * * * root hedera-web.php -m misc/exchange-rate
0 0 * * * root hedera-web.php -m image/sync
0 1 * * * root /usr/share/hedera-web/utils/image-clean.sh > /dev/null
0 */1 * * * root /usr/share/hedera-web/utils/update-browscap.sh > /dev/null

View File

@ -1,9 +1,47 @@
version: '3.7'
services:
main:
image: registry.verdnatura.es/verdnatura/hedera-web:${TAG:?}
image: registry.verdnatura.es/hedera-web:${VERSION:?}
build:
context: .
dockerfile: Dockerfile
args:
- VERSION=${VERSION:?}
ports:
- 80
configs:
- source: config
target: /etc/hedera-web/config.my.php
volumes:
- /mnt/appdata:/mnt/storage
- /mnt/appdata/image:/var/lib/hedera-web/image-db
- /mnt/appdata/vn-access:/var/lib/hedera-web/vn-access
deploy:
replicas: ${MAIN_REPLICAS:?}
placement:
constraints:
- node.role == worker
resources:
limits:
memory: 2G
cron:
image: registry.verdnatura.es/hedera-web:${VERSION:?}
command: 'cron -f'
configs:
- source: config
target: /etc/hedera-web/config.my.php
volumes:
- /mnt/appdata:/mnt/storage
- /mnt/appdata/image:/var/lib/hedera-web/image-db
deploy:
replicas: ${CRON_REPLICAS:?}
placement:
constraints:
- node.role == worker
resources:
limits:
memory: 1G
configs:
config:
external: true
name: ${PROJECT_NAME:?}-${BRANCH_NAME:?}

View File

@ -65,8 +65,8 @@
one-way="true"
one-time="true">
<db-model property="model">
SELECT id, name FROM vn.country
ORDER BY name
SELECT id, country FROM vn.country
ORDER BY country
</db-model>
</htk-combo>
</div>

View File

@ -18,8 +18,8 @@
LEFT JOIN image im
ON im.collectionFk = 'catalog'
AND im.name = i.image
WHERE i.isActive
AND (i.longName LIKE CONCAT('%', #search, '%') OR i.id = #search)
WHERE i.longName LIKE CONCAT('%', #search, '%')
OR i.id = #search
ORDER BY i.longName LIMIT 50
</db-model>
<custom>

View File

@ -275,7 +275,7 @@
}
& > .htk-image {
width: 100%;
height: 210px;
height: 180px;
& > img {
height: initial;

View File

@ -117,7 +117,7 @@
SELECT i.id, i.longName item, i.subName,
i.tag5, i.value5, i.tag6, i.value6,
i.tag7, i.value7, i.tag8, i.value8,
i.relevancy, i.size, i.category, b.minQuantity,
i.relevancy, i.size, i.category, i.minQuantity,
k.name ink, p.name producer, o.name origin,
b.available, b.price, b.`grouping`,
i.image, im.updated
@ -126,13 +126,19 @@
LEFT JOIN vn.ink k ON k.id = i.inkFk
LEFT JOIN vn.producer p ON p.id = i.producerFk
LEFT JOIN vn.origin o ON o.id = i.originFk
LEFT JOIN image im ON im.collectionFk = 'catalog'
LEFT JOIN image im
ON im.collectionFk = 'catalog'
AND im.name = i.image
WHERE b.available > 0
ORDER BY i.relevancy DESC, i.name, i.size
LIMIT 5000;
DROP TEMPORARY TABLE tmp.item;
CALL vn.ticketCalculatePurge();
DROP TEMPORARY TABLE
tmp.item,
tmp.ticketCalculateItem,
tmp.ticketComponentPrice,
tmp.ticketComponent,
tmp.ticketLot,
tmp.zoneGetShipped;
</db-model>
<db-form id="$card" v-model="card" model="items"/>
<vn-lot id="card-lot"/>

View File

@ -120,7 +120,7 @@
form-id="iter"
on-change="onAddressChange">
<db-model property="model" id="addresses">
SELECT a.id, a.nickname, p.name province, a.city, a.street, a.isActive, c.name
SELECT a.id, a.nickname, p.name province, a.city, a.street, a.isActive, c.country
FROM myAddress a
LEFT JOIN vn.province p ON p.id = a.provinceFk
JOIN vn.country c ON c.id = p.countryFk

View File

@ -67,7 +67,7 @@ export default new Class({
methods = ['balance'];
selectedMethod = 'BALANCE';
} else {
methods = ['card'];
methods = ['card', 'transfer', 'later'];
if (!creditExceededCond) {
methods.push('credit');
@ -98,6 +98,9 @@ export default new Class({
case 'CARD':
id = 'cardMethod';
break;
case 'TRANSFER':
id = 'transferMethod';
break;
default:
id = null;
}

View File

@ -162,6 +162,32 @@
<t>You will be redirected to the payment.</t>
</div>
</div>
<div id="transfer-method">
<label>
<htk-radio radio-group="pay-method" value="TRANSFER"/>
<t>Bank Transfer</t>
</label>
<div>
<t>Make a transfer to one account.</t>
<htk-repeater form-id="iter">
<db-model property="model">
SELECT name, iban FROM mainAccountBank
</db-model>
<custom>
<div class="transfer-account">
<p>{{iter.name}}</p>
<p>{{iter.iban}}</p>
</div>
</custom>
</htk-repeater>
</div>
</div>
<div id="later-method">
<label>
<htk-radio radio-group="pay-method" value="LATER"/>
<t>Pay later</t>
</label>
</div>
</div>
</div>
<div class="button-bar vn-mt-md">

View File

@ -3,17 +3,30 @@ import './style.scss';
export default new Class({
Extends: Hedera.Form,
Template: require('./ui.xml'),
donwloadRenderer(column, invoice) {
var invoiceId = invoice.$.id;
onDownloadClick(column, value, row) {
var model = this.$.invoices;
var hasPdf = model.get(row, 'hasPdf');
var id = model.get(row, 'id');
if (invoice.$.hasPdf && invoiceId) {
var params = {
srv: 'rest:dms/invoice',
invoice: invoiceId,
access_token: this.conn.token
};
if (hasPdf && id) {
let params = Vn.Url.makeUri({ access_token: this.conn.token });
window.open(`/api/InvoiceOuts/${id}/download?${params}`);
Object.assign(column, {
tip: _('Download PDF'),
disabled: false,
icon: 'download',
href: '?'+ Vn.Url.makeUri(params)
});
} else
Htk.Toast.showWarning(_('Request the invoice to your salesperson'));
Object.assign(column, {
tip: _('Request the invoice to your salesperson'),
disabled: true,
icon: 'warning',
href: null
});
}
});

View File

@ -6,7 +6,7 @@
<htk-grid
class="box vn-w-sm"
show-header="false">
<db-model property="model" id="invoices">
<db-model property="model" id="tickets">
SELECT id, ref, issued, amount, hasPdf
FROM myInvoice
ORDER BY issued DESC
@ -16,9 +16,8 @@
<htk-column-date title="_Date" column="issued" format="_%e %b %Y"/>
<htk-column-spin title="_Import" column="amount" unit="€" digits="2"/>
<htk-column-button
icon="download"
tip="_Download PDF"
on-clicked="onDownloadClick"/>
renderer="donwloadRenderer"
target="_blank"/>
</htk-grid>
</div>
</vn>

View File

@ -26,8 +26,8 @@
<label><t>Realm</t></label>
<htk-combo form="lot" column="realm" not-null="false">
<db-model property="model">
SELECT id, name FROM vn.itemCategory
WHERE display ORDER BY name
SELECT id, reino FROM vn2008.reinos
WHERE display != FALSE ORDER BY reino
</db-model>
</htk-combo>
</div>

View File

@ -25,9 +25,9 @@
on-ready="this.onConfigChange()">
<db-model property="model">
SELECT c.id, c.name reportTitle, c.namePrefix, c.warehouse, c.family,
c.shelf, c.maxAmount, c.showPacking, c.stack, it.categoryFk realm
FROM shelfMultiConfig c
JOIN vn.itemType it ON it.id = c.family
c.shelf, c.maxAmount, c.showPacking, c.stack, t.reino_id realm
FROM shelfConfig c
JOIN vn2008.Tipos t ON t.tipo_id = c.family
</db-model>
</htk-combo>
</div>
@ -39,8 +39,8 @@
<label><t>Reign</t></label>
<htk-combo form="lot" name="realm">
<db-model property="model">
SELECT id, name FROM vn.itemCategory
WHERE display ORDER BY name
SELECT id, reino FROM vn2008.reinos
WHERE display != FALSE ORDER BY reino
</db-model>
</htk-combo>
</div>
@ -48,8 +48,8 @@
<label><t>Family</t></label>
<htk-combo form="lot" name="family">
<db-model property="model" lot="lot">
SELECT id, name FROM vn.itemType
WHERE categoryFk = #realm ORDER BY name
SELECT tipo_id, Tipo FROM vn2008.Tipos
WHERE reino_id = #realm ORDER BY Tipo
</db-model>
</htk-combo>
</div>

View File

@ -1,6 +1,6 @@
{
"name": "hedera-web",
"version": "25.4.4",
"version": "24.8.2",
"description": "Verdnatura web page",
"license": "GPL-3.0",
"repository": {

21
rest/dms/invoice.php Normal file
View File

@ -0,0 +1,21 @@
<?php
use Vn\Web\Security;
use Vn\Web\Util;
use Vn\Lib;
class Invoice extends Vn\Web\RestRequest {
const PARAMS = ['invoice'];
const SECURITY = Security::INVOKER;
function run($db) {
$pdfPath = $db->getValueFromFile(__DIR__ .'/invoice',
['invoice' =>(int) $_GET['invoice']]);
if (!$pdfPath)
throw new Lib\UserException(s('Invoice id not found'));
Util::printFile($pdfPath);
}
}

5
rest/dms/invoice.sql Normal file
View File

@ -0,0 +1,5 @@
SELECT CONCAT_WS('/', c.pdfsDir, vn.invoiceOut_getPath(#invoice))
FROM config c
JOIN myInvoice i
WHERE i.id = #invoice

View File

@ -8,7 +8,7 @@ class Clean extends Edi\Method {
$cleanPeriod = $db->getValue(
"SELECT ic.cleanPeriod
FROM imapMultiConfig ic
FROM imapConfig ic
JOIN util.config c ON c.environment = ic.environment");
$deleted = 0;

View File

@ -14,7 +14,7 @@ abstract class Method extends \Vn\Lib\Method {
$imapConf = $db->getRow(
"SELECT ic.host, ic.user, ic.pass, ic.successFolder, ic.errorFolder
FROM imapMultiConfig ic
FROM imapConfig ic
JOIN util.config c ON c.environment = ic.environment");
$this->mailbox = sprintf('{%s/imap/ssl/novalidate-cert}',

View File

@ -0,0 +1,41 @@
<?php
/**
* Ejemplo:
* <Cube><Cube time="2010-12-10"><Cube currency="USD" rate="1.3244"/>
*/
class ExchangeRate extends Vn\Lib\Method {
function run($db) {
$db->selectDb('vn2008');
// Indica la URL del archivo
$xml = new SimpleXMLElement(
'http://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist-90d.xml', 0, TRUE);
$date = $db->getValue("SELECT MAX(date) fecha FROM reference_rate");
$maxDate = $date ? DateTime::createFromFormat('Y-m-d', $date) : NULL;
foreach ($xml->Cube[0]->Cube as $cube) {
$xmlDate = new DateTime($cube['time']);
// Si existen datos más recientes de la máxima fecha los añade
if ($maxDate <= $xmlDate)
foreach ($cube->Cube as $subCube)
if ($subCube['currency'] == 'USD') {
$params = [
'date' => $xmlDate,
'rate' => $subCube['rate']
];
$db->query(
'REPLACE INTO reference_rate(moneda_id, date, rate)
VALUES(2, #date, #rate)',
$params
);
}
}
$db->queryFromFile(__DIR__.'/exrate-add');
}
}

6
rest/misc/exrate-add.sql Normal file
View File

@ -0,0 +1,6 @@
INSERT INTO reference_rate (moneda_id, date, rate)
SELECT 2, TIMESTAMPADD (DAY, 1, r1.date), r1.rate
FROM reference_rate r1
LEFT JOIN reference_rate r2
ON TIMESTAMPADD(DAY, 1, r1.date) = r2.date
WHERE r2.date IS NULL AND r1.date < TIMESTAMPADD (DAY, -2, CURDATE())