From 98125196770cefcb70b8a3e62613a8ba6abb694b Mon Sep 17 00:00:00 2001 From: Juan Ferrer Toribio Date: Fri, 26 Aug 2016 14:43:45 +0200 Subject: [PATCH] One unique entry point from HTTP server --- hedera.php => cli.php | 2 +- debian/cron.d | 8 +- debian/install | 23 +-- forms/cms/contact/contact.js | 9 +- forms/cms/contact/ui.xml | 5 +- forms/ecomerce/invoices/invoices.js | 2 +- index.php | 6 +- js/htk/image-editor.xml | 3 +- js/vn/json-request.js | 47 ++--- json.php | 8 - rest.php | 8 - rest/edi/clean.php | 49 +++++ rest/edi/lib/message.php | 165 ++++++++++++++++ rest/edi/lib/method.php | 43 +++++ rest/edi/lib/section.php | 28 +++ rest/edi/lib/segment.php | 38 ++++ rest/edi/load.php | 221 ++++++++++++++++++++++ rest/edi/plsql/batch_new.sql | 169 +++++++++++++++++ rest/edi/plsql/edi_load.sql | 164 ++++++++++++++++ rest/edi/plsql/message_new.sql | 27 +++ rest/edi/schemas/CLOCKT.json | 15 ++ rest/edi/sql/batch-add.sql | 6 + rest/edi/sql/bucket.sql | 14 ++ rest/edi/sql/bucket_type.sql | 10 + rest/edi/sql/feature.sql | 11 ++ rest/edi/sql/genus.sql | 10 + rest/edi/sql/item.sql | 13 ++ rest/edi/sql/item_feature.sql | 12 ++ rest/edi/sql/item_group.sql | 10 + rest/edi/sql/plant.sql | 11 ++ rest/edi/sql/specie.sql | 11 ++ rest/edi/sql/supplier.sql | 10 + rest/edi/sql/type.sql | 11 ++ rest/edi/sql/value.sql | 11 ++ rest/edi/update.php | 119 ++++++++++++ rest/image/resize.php | 2 +- rest/image/sync.php | 2 +- rest/misc/exchange-rate.php | 54 ++++++ rest/misc/exrate-add.sql | 6 + rest/misc/mail.php | 91 +++++++++ rest/tpv/confirm-mail.php | 10 +- vn/web/app.php | 143 +++----------- vn/web/{html-app.php => html-service.php} | 15 +- vn/web/{json-app.php => json-service.php} | 8 +- vn/web/{rest-app.php => rest-service.php} | 12 +- vn/web/service.php | 139 ++++++++++++++ 46 files changed, 1579 insertions(+), 202 deletions(-) rename hedera.php => cli.php (55%) delete mode 100755 json.php delete mode 100755 rest.php create mode 100644 rest/edi/clean.php create mode 100644 rest/edi/lib/message.php create mode 100644 rest/edi/lib/method.php create mode 100644 rest/edi/lib/section.php create mode 100644 rest/edi/lib/segment.php create mode 100644 rest/edi/load.php create mode 100644 rest/edi/plsql/batch_new.sql create mode 100644 rest/edi/plsql/edi_load.sql create mode 100644 rest/edi/plsql/message_new.sql create mode 100644 rest/edi/schemas/CLOCKT.json create mode 100644 rest/edi/sql/batch-add.sql create mode 100644 rest/edi/sql/bucket.sql create mode 100644 rest/edi/sql/bucket_type.sql create mode 100644 rest/edi/sql/feature.sql create mode 100644 rest/edi/sql/genus.sql create mode 100644 rest/edi/sql/item.sql create mode 100644 rest/edi/sql/item_feature.sql create mode 100644 rest/edi/sql/item_group.sql create mode 100644 rest/edi/sql/plant.sql create mode 100644 rest/edi/sql/specie.sql create mode 100644 rest/edi/sql/supplier.sql create mode 100644 rest/edi/sql/type.sql create mode 100644 rest/edi/sql/value.sql create mode 100644 rest/edi/update.php create mode 100755 rest/misc/exchange-rate.php create mode 100644 rest/misc/exrate-add.sql create mode 100755 rest/misc/mail.php mode change 100755 => 100644 vn/web/app.php rename vn/web/{html-app.php => html-service.php} (90%) rename vn/web/{json-app.php => json-service.php} (92%) rename vn/web/{rest-app.php => rest-service.php} (93%) create mode 100755 vn/web/service.php diff --git a/hedera.php b/cli.php similarity index 55% rename from hedera.php rename to cli.php index 6fa654af..e0538a82 100755 --- a/hedera.php +++ b/cli.php @@ -2,7 +2,7 @@ require_once ('vn/lib/cli-app.php'); -$cliApp = new Vn\Lib\CliApp ('hedera-web', 'rest'); +$cliApp = new Vn\Lib\CliApp ('hedera-web'); $cliApp->run (); ?> diff --git a/debian/cron.d b/debian/cron.d index 2a9461b4..d26b7a7c 100644 --- a/debian/cron.d +++ b/debian/cron.d @@ -1,2 +1,8 @@ MAILTO=webmaster -*/4 * * * * www-data php5 /usr/share/hedera-web/tpv/imap.php +*/4 * * * * root php /usr/share/hedera-web/cli.php -m tpv/confirm-mail +*/2 * * * * root php /usr/share/hedera-web/cli.php -m edi/load +0 23 * * * root php /usr/share/hedera-web/cli.php -m edi/clean +0 5 * * * root php /usr/share/hedera-web/cli.php -m edi/update +*/1 * * * * root php /usr/share/hedera-web/cli.php -m misc/mail +0 5 * * * root php /usr/share/hedera-web/cli.php -m misc/exchange-rate +45 14 20 11 * root php /usr/share/hedera-web/cli.php -m misc/exchange-rate diff --git a/debian/install b/debian/install index 35d0221f..f8f50518 100644 --- a/debian/install +++ b/debian/install @@ -1,17 +1,12 @@ conf/* etc/hedera-web vn usr/share/php doc/* usr/share/doc/hedera-web -forms usr/share/hedera-web/web -image usr/share/hedera-web/web -js usr/share/hedera-web/web -locale usr/share/hedera-web/web -pages usr/share/hedera-web/web -reports usr/share/hedera-web/web -rest usr/share/hedera-web/web -rest-json usr/share/hedera-web/web -index.php usr/share/hedera-web/web -rest.php usr/share/hedera-web/web -rest-json.php usr/share/hedera-web/web -hedera.php usr/share/hedera-web/bin -tasks usr/share/hedera-web/bin - +forms usr/share/hedera-web +image usr/share/hedera-web +js usr/share/hedera-web +locale usr/share/hedera-web +pages usr/share/hedera-web +reports usr/share/hedera-web +rest usr/share/hedera-web +index.php usr/share/hedera-web +cli.php usr/share/hedera-web diff --git a/forms/cms/contact/contact.js b/forms/cms/contact/contact.js index a52f06df..8dee47e2 100644 --- a/forms/cms/contact/contact.js +++ b/forms/cms/contact/contact.js @@ -14,8 +14,13 @@ Vn.Contact = new Class ,refreshCaptcha: function () { - var url = 'rest.php?method=core/captcha'; - this.$('captcha-img').src = url +'&stamp='+ new Date ().getTime (); + params = { + 'srv': 'rest:core/captcha', + 'stamp': new Date ().getTime () + }; + this.$('captcha-img').src = '?'+ Vn.Url.makeUri (params); + + Vn.Url.makeUri (params) } ,onSubmit: function () diff --git a/forms/cms/contact/ui.xml b/forms/cms/contact/ui.xml index 3121df5a..bcb3afe2 100755 --- a/forms/cms/contact/ui.xml +++ b/forms/cms/contact/ui.xml @@ -12,9 +12,8 @@ OrCallUs

+ id="contact-form"> +
diff --git a/forms/ecomerce/invoices/invoices.js b/forms/ecomerce/invoices/invoices.js index 7c8cff50..959821e6 100644 --- a/forms/ecomerce/invoices/invoices.js +++ b/forms/ecomerce/invoices/invoices.js @@ -8,7 +8,7 @@ Vn.Invoices = new Class if (!invoiceId) return; - var url = 'rest.php?method=invoice&invoice='+ invoiceId; + var url = 'rest.php?method=dms/invoice&invoice='+ invoiceId; window.open (url, '_blank'); } }); diff --git a/index.php b/index.php index 0bb41cf7..8461c7d7 100755 --- a/index.php +++ b/index.php @@ -1,8 +1,8 @@ run (); +$webApp = new Vn\Web\App ('hedera-web'); +$webApp->run (); ?> diff --git a/js/htk/image-editor.xml b/js/htk/image-editor.xml index 5f508659..37161386 100644 --- a/js/htk/image-editor.xml +++ b/js/htk/image-editor.xml @@ -2,9 +2,8 @@
+
diff --git a/js/vn/json-request.js b/js/vn/json-request.js index 68706139..f0967eda 100644 --- a/js/vn/json-request.js +++ b/js/vn/json-request.js @@ -21,10 +21,34 @@ Vn.JsonRequest = new Class ,send: function (params, callback) { - var url = 'json.php?method='+ encodeURIComponent (this._methodName); + params['srv'] = 'json:'+ this._methodName; this.sendWithUrl (params, callback, 'post', url); } + ,sendForm: function (form, callback) + { + var params = {}; + var elements = form.elements; + + for (var i = 0; i < elements.length; i++) + if (elements[i].name) + params[elements[i].name] = elements[i].value; + + this.sendWithUrl (params, callback, form.method, form.action); + } + + ,sendFormMultipart: function (form, callback) + { + var formData = new FormData (form); + formData.append ('service', 'Json'); + + var request = new XMLHttpRequest (); + request.open (form.method, form.action, true); + request.onreadystatechange = + this._onStateChange.bind (this, request, callback); + request.send (new FormData (form)); + } + ,_onStateChange: function (request, callback) { if (request.readyState !== 4) @@ -63,26 +87,5 @@ Vn.JsonRequest = new Class if (callback) callback (this, data, error); } - - ,sendForm: function (form, callback) - { - var params = {}; - var elements = form.elements; - - for (var i = 0; i < elements.length; i++) - if (elements[i].name) - params[elements[i].name] = elements[i].value; - - this.sendWithUrl (params, callback, form.method, form.action); - } - - ,sendFormMultipart: function (form, callback) - { - var request = new XMLHttpRequest (); - request.open (form.method, form.action, true); - request.onreadystatechange = - this._onStateChange.bind (this, request, callback); - request.send (new FormData (form)); - } }); diff --git a/json.php b/json.php deleted file mode 100755 index 9131590e..00000000 --- a/json.php +++ /dev/null @@ -1,8 +0,0 @@ -run (); - -?> diff --git a/rest.php b/rest.php deleted file mode 100755 index 7905fd5f..00000000 --- a/rest.php +++ /dev/null @@ -1,8 +0,0 @@ -run (); - -?> diff --git a/rest/edi/clean.php b/rest/edi/clean.php new file mode 100644 index 00000000..0448e120 --- /dev/null +++ b/rest/edi/clean.php @@ -0,0 +1,49 @@ +getSysConn (); + $imap = $this->imap; + + $cleanPeriod = $db->getValue ('SELECT clean_period FROM imap_config'); + + $deleted = 0; + $date = new DateTime (NULL); + $date->sub (new DateInterval ($cleanPeriod)); + $filter = sprintf ('BEFORE "%s"', $date->format('D, j M Y')); + + $folders = [ + $this->imapConf['success_folder'] + ,$this->imapConf['error_folder'] + ]; + + foreach ($folders as $folder) + if (imap_reopen ($imap, $this->mailbox .'.'. $folder)) + { + if ($messages = imap_search ($imap, $filter)) + { + foreach ($messages as $message) + imap_delete ($imap, $message); + + imap_expunge ($imap); + $count = count ($messages); + $deleted += $count; + } + else + $count = 0; + + printf ('%d mails deleted from %s mailbox.' + ,$count + ,$folder + ); + } + + printf ('Total: %d mails deleted.', $deleted); + } +} + +?> diff --git a/rest/edi/lib/message.php b/rest/edi/lib/message.php new file mode 100644 index 00000000..baf769a9 --- /dev/null +++ b/rest/edi/lib/message.php @@ -0,0 +1,165 @@ +schema = $schema; + $info->parentInfo = NULL; + $info->section = NULL; + $topInfo = $info; + + try { + while (TRUE) + { + $segment = $this->parseSegment ($string, $pos); + + if (!$segment && (!$endTag || !$info)) + break; + + if (!$segment || ($segment && !$info)) + throw new \Exception (); + + if ($firstLoop) + { + if ($segment->name != $info->schema['mainTag']) + throw new \Exception (); + } + else + { + for ($i = $info; $i; $i = $i->parentInfo) + if (isset ($i->schema['childs'][$segment->name])) + { + $info = new SectionInfo (); + $info->schema = $i->schema['childs'][$segment->name]; + $info->parentInfo = $i; + $newSection = TRUE; + break; + } + } + + if ($newSection) + { + $section = new Section (); + $section->name = $segment->name; + $info->section = $section; + + if ($info->parentInfo) + { + $section->parent = $info->parentInfo->section; + $section->parent->childs[$segment->name][] = $section; + } + + if (isset ($info->schema['endTag'])) + $endTag = $info; + + $newSection = FALSE; + } + + if ($endTag && $endTag->schema['endTag'] == $segment->name) + { + $endTag->section->segments[] = $segment; + $info = $endTag->parentInfo; + + for ($i = $info; $i; $i = $i->parentInfo) + if (isset ($i->schema['endTag'])) + { + $endTag = $i; + break; + } + } + else + $info->section->segments[] = $segment; + + $firstLoop = FALSE; + }} + catch (\Exception $e) + { + throw new \Exception (sprintf ('Parse error, something is wrong near "%s"', + substr ($string, $pos, 10))); + } + + $this->section = $topInfo->section; + } + + function parseSegment (&$string, &$pos) + { + $empty = TRUE; + $values = []; + + while (TRUE) + { + if (!isset ($string{$pos})) + return NULL; + + if (in_array ($string{$pos}, ['+', ':', '\''])) + { + if (!$empty) + { + $values[] = + trim (substr ($string, $start, $pos - $start)); + $empty = TRUE; + } + } + elseif ($empty) + { + $start = $pos; + $empty = FALSE; + } + + if ($string{$pos} === '\'') + break; + + $pos++; + } + + $pos++; + + $segment = new Segment (); + $segment->name = $values[0]; + $segment->values = $values; + return $segment; + } +} + +?> diff --git a/rest/edi/lib/method.php b/rest/edi/lib/method.php new file mode 100644 index 00000000..cd7cda7f --- /dev/null +++ b/rest/edi/lib/method.php @@ -0,0 +1,43 @@ +getSysConn (); + $db->selectDb ('edi'); + + $imapConf = $db->getRow ( + 'SELECT host, user, pass, success_folder, error_folder FROM imap_config'); + + $this->mailbox = sprintf ('{%s/imap/ssl/novalidate-cert}INBOX', + $imapConf['host']); + + $imap = imap_open ($this->mailbox + ,$imapConf['user'] + ,base64_decode ($imapConf['pass']) + ); + + $this->imap = $imap; + $this->imapConf = $imapConf; + + if ($imap) + { + $this->ediRun (); + imap_expunge ($imap); + imap_close ($imap); + } + else + error_log (imap_last_error ()); + } +} + +?> diff --git a/rest/edi/lib/section.php b/rest/edi/lib/section.php new file mode 100644 index 00000000..3aa0fdcf --- /dev/null +++ b/rest/edi/lib/section.php @@ -0,0 +1,28 @@ +segments as $segment) + if ($segment->name == $name + && (!$subname || $segment->values[1] == $subname)) + return $segment->getValue ($key, $type); + + if ($this->parent) + return $this->parent->getValue ($name, $key, $type, $subname); + + return NULL; + } +} + +?> diff --git a/rest/edi/lib/segment.php b/rest/edi/lib/segment.php new file mode 100644 index 00000000..8d7adfe0 --- /dev/null +++ b/rest/edi/lib/segment.php @@ -0,0 +1,38 @@ += count ($this->values)) + return NULL; + + $v = $this->values[$key]; + + switch ($type) + { + case TYPE_DATE: + $tmp = new \Date (); + $tmp->setDate (substr ($v, 0, 4), substr ($v, 4, 2), substr ($v, 6, 2)); + return $tmp; + case TYPE_TIME: + $tmp = new \Time (); + $tmp->setTime (substr ($v, 0, 2), substr ($v, 2, 2)); + return $tmp; + case TYPE_DOUBLE: + case TYPE_INTEGER: + set_type ($v, $type); + default: + return $v; + } + } +} + +?> diff --git a/rest/edi/load.php b/rest/edi/load.php new file mode 100644 index 00000000..8fd59902 --- /dev/null +++ b/rest/edi/load.php @@ -0,0 +1,221 @@ +getSysConn (); + $this->ediSchema = Edi\Message::loadSchema ('CLOCKT'); + + if (!$this->ediSchema) + throw new Exception ('Can not load EDI schema.'); + + $this->params = $db->query ( + 'SELECT code, name, subname, position, type, required FROM param'); + + $inbox = imap_search ($this->imap, 'ALL'); + + if ($inbox) + { + foreach ($inbox as $msg) + $this->loadMail ($msg); + + $inboxCount = count ($inbox); + + if ($inboxCount > 0) + printf ('Total: %d messages readed.', $inboxCount); + } + } + + function loadMail ($msg) + { + $db = $this->getSysConn (); + $imap = $this->imap; + + // Gets EKT messages from email + + $msgStructure = imap_fetchstructure ($imap, $msg); + $result = []; + + // Gets the mail sender and Message-ID + + $header = imap_headerinfo ($imap, $msg); + $from = $header->from; + $mailId = trim ($header->message_id, '<>'); + + if ($from && count ($from) > 0) + $sender = $from[0]->mailbox .'@'. $from[0]->host; + else + $sender = NULL; + + // Searches the EDI message on mail parts + + $matchTypes = [TYPEAPPLICATION, TYPETEXT]; + $this->imapFindParts ($msgStructure, $matchTypes, [], $result); + + $count = 0; + $error = NULL; + + foreach ($result as $msgSection) + try + { + $part = imap_bodystruct ($imap, $msg, $msgSection); + $ediString = imap_fetchbody ($imap, $msg, $msgSection); + + switch ($part->encoding) + { + case ENCBASE64: + $ediString = imap_base64 ($ediString); + break; + case ENCQUOTEDPRINTABLE: + $ediString = imap_qprint ($ediString); + break; + } + + if (!Edi\Message::isEdiString ($ediString)) + continue; + + // Creates the EDI object and loads its exchanges + + $ediMessage = new Edi\Message (); + $ediMessage->parse ($ediString, $this->ediSchema); + + $db->query ('START TRANSACTION'); + $db->query ('CALL message_new (#mailId, #sender, @message)', + [ + 'mailId' => $mailId, + 'sender' => $sender + ]); + + $unb = $ediMessage->section; + $unhs = $unb->childs['UNH']; + + foreach ($unhs as $unh) + foreach ($lins = $unh->childs['LIN'] as $lin) + { + $ediValues = []; + + // Gets the exchange params + + $this->params->data_seek (0); + + while ($row = $this->params->fetch_assoc ()) + { + switch ($row['type']) + { + case 'INTEGER': + $type = TYPE_INTEGER; + break; + case 'DOUBLE': + $type = TYPE_DOUBLE; + break; + case 'DATE': + $type = TYPE_DATE; + break; + case 'TIME': + $type = TYPE_TIME; + break; + default: + $type = TYPE_STRING; + } + + $value = $lin->getValue ( + $row['name'], $row['position'], $type, $row['subname']); + + if (!isset ($value) && $row['required']) + throw new Exception ('Missing required parameter: '. $row['code']); + + $ediValues[$row['code']] = $value; + } + + // Gets the exchange features + + $res = $db->query ( + 'SELECT presentation_order, feature ' + .'FROM item_feature WHERE item_id = #ref ' + .'AND expiry_date IS NULL' + ,$ediValues + ); + + if ($res) + while ($row = $res->fetch_assoc ()) + { + $value = $lin->getValue ('IMD', 2, TYPE_INTEGER, $row['feature']); + $ediValues['s'.$row['presentation_order']] = $value; + } + else + throw new Exception ('Can\'t get the item features.'); + + for ($i = 1; $i <= 6; $i++) + if (!isset ($ediValues['s'.$i])) + $ediValues['s'.$i] = NULL; + + // Adds the exchange to the Database + + $res = $db->queryFromFile ('sql/batch-add', $ediValues); + + if (!$res) + throw new Exception ('Failed to insert the line.'); + + $count++; + } + + $db->query ('COMMIT'); + } + catch (Exception $e) + { + $db->query ('ROLLBACK'); + $error = $e->getMessage (); + break; + } + + if (!$error && $count == 0) + $error = 'EDI messages not found.'; + + // Logs information of realized operations + + if (!$error) + { + $folder = $this->imapConf['success_folder']; + printf ('EDI: Mail loaded with %d lines.', $count); + } + else + { + $folder = $this->imapConf['error_folder']; + printf ('EDI: Mail error: %s', $error); + } + + // Moves the mail to another folder + + $folder = sprintf ('INBOX.%s', $folder); + + if (!imap_mail_move ($imap, $msg, $folder)) + error_log ('Can\'t move message to %s: %s' + ,$folder + ,imap_last_error () + ); + } + + function imapFindParts (&$part, &$matchTypes, $section, &$result) + { + if (in_array ($part->type, $matchTypes)) + { + if (count ($section) > 0) + $result[] = implode ('.', $section); + else + $result[] = '1'; + } + elseif ($part->type == TYPEMULTIPART) + foreach ($part->parts as $i => $subpart) + { + array_push ($section, $i + 1); + $this->imapFindParts ($subpart, $matchTypes, $section, $result); + array_pop ($section); + } + } +} + +?> diff --git a/rest/edi/plsql/batch_new.sql b/rest/edi/plsql/batch_new.sql new file mode 100644 index 00000000..9f1c60ca --- /dev/null +++ b/rest/edi/plsql/batch_new.sql @@ -0,0 +1,169 @@ +/** + * Adds a new lot, generates its barcode + * inserts/updates de record on table #vn2008.buy_edi + **/ +USE edi; +DROP PROCEDURE IF EXISTS batch_new; +DELIMITER $$ +CREATE PROCEDURE batch_new ( + v_message INT + ,v_type MEDIUMINT + ,v_delivery_number BIGINT + ,v_fec DATE + ,v_hor TIME + ,v_ref INT + ,v_agj INT + ,v_cat VARCHAR(2) + ,v_pac INT + ,v_sub MEDIUMINT + ,v_kop INT + ,v_ptd VARCHAR(6) + ,v_pro MEDIUMINT + ,v_ori VARCHAR(3) + ,v_ptj MEDIUMINT + ,v_qty INT + ,v_pri DOUBLE + ,v_klo SMALLINT + ,v_s1 VARCHAR(3) + ,v_s2 VARCHAR(3) + ,v_s3 VARCHAR(3) + ,v_s4 VARCHAR(4) + ,v_s5 VARCHAR(3) + ,v_s6 VARCHAR(3) + ,v_k1 SMALLINT + ,v_k2 SMALLINT + ,v_p1 TINYINT + ,v_p2 TINYINT + ,v_auction SMALLINT + ,v_package INT +) +BEGIN + DECLARE v_edi INT; + DECLARE v_barcode CHAR(15) DEFAULT NULL; + DECLARE v_is_duplicated BOOLEAN DEFAULT FALSE; + DECLARE v_update_existent BOOLEAN DEFAULT FALSE; + + DECLARE CONTINUE HANDLER FOR 1062 -- ER_DUP_KEY + SET v_is_duplicated = TRUE; + + -- Genera el código de barras + + IF v_agj != 0 AND v_agj IS NOT NULL + THEN + SET v_barcode = CONCAT( + LPAD(v_auction, 2, 0), + LPAD(IFNULL(v_klo, 99), 2, 0), + LPAD(DAYOFYEAR(v_fec), 3, 0), + IF(v_klo IS NULL OR v_klo = 99, + LPAD(v_agj, 7, 0), + CONCAT(LPAD(v_agj, 5, 0), '01') + ), + '0' + ); + END IF; + + IF v_kop IS NULL + THEN + SELECT default_kop INTO v_kop FROM config; + END IF; + + -- Inserta el nuevo EKT + + INSERT INTO vn2008.buy_edi SET + barcode = IFNULL(v_barcode, barcode) + ,delivery_number = v_delivery_number + ,entry_year = YEAR(v_fec) + ,fec = v_fec + ,hor = v_hor + ,ref = v_ref + ,agj = v_agj + ,cat = v_cat + ,pac = v_pac + ,sub = v_sub + ,kop = v_kop + ,ptd = v_ptd + ,pro = v_pro + ,ori = v_ori + ,ptj = v_ptj + ,qty = v_qty + ,pri = v_pri + ,klo = v_klo + ,s1 = v_s1 + ,s2 = v_s2 + ,s3 = v_s3 + ,s4 = v_s4 + ,s5 = v_s5 + ,s6 = v_s6 + ,k01 = v_k1 + ,k02 = v_k2 + ,k03 = v_p1 + ,k04 = v_p2 + ,auction = v_auction + ,package = v_package; + + + -- Si el EKT está duplicado y el que habia en la tabla era uno + -- provisional, lo actualiza con los nuevos valores. + + IF NOT v_is_duplicated + THEN + SET v_edi = LAST_INSERT_ID(); + CALL edi_load (v_edi); + + ELSEIF v_delivery_number != 0 + AND v_delivery_number IS NOT NULL + THEN + SELECT id INTO v_edi + FROM vn2008.buy_edi + WHERE delivery_number = v_delivery_number; + + SELECT COUNT(*) = 0 INTO v_update_existent + FROM vn2008.buy_edi e + JOIN batch b ON b.buy_edi_id = e.id + JOIN config c + WHERE e.delivery_number = v_delivery_number + AND b.type_id != c.presale_id; + END IF; + + IF v_update_existent + THEN + UPDATE vn2008.buy_edi SET + barcode = IFNULL(v_barcode, barcode) + ,fec = v_fec + ,hor = v_hor + ,ref = v_ref + ,agj = v_agj + ,cat = v_cat + ,pac = v_pac + ,sub = v_sub + ,kop = v_kop + ,ptd = v_ptd + ,pro = v_pro + ,ori = v_ori + ,ptj = v_ptj + ,qty = v_qty + ,pri = v_pri + ,klo = v_klo + ,s1 = v_s1 + ,s2 = v_s2 + ,s3 = v_s3 + ,s4 = v_s4 + ,s5 = v_s5 + ,s6 = v_s6 + ,k01 = v_k1 + ,k02 = v_k2 + ,k03 = v_p1 + ,k04 = v_p2 + ,auction = v_auction + ,package = v_package + WHERE id = v_edi; + END IF; + + -- Registra el lote + + INSERT INTO batch SET + message_id = v_message + ,type_id = v_type + ,buy_edi_id = v_edi; +END$$ +DELIMITER ; diff --git a/rest/edi/plsql/edi_load.sql b/rest/edi/plsql/edi_load.sql new file mode 100644 index 00000000..6dea81e2 --- /dev/null +++ b/rest/edi/plsql/edi_load.sql @@ -0,0 +1,164 @@ +/** + * Creates a buy line from an EDI lot. + * + * @param v_edi The EDI id + **/ +USE edi; +DROP PROCEDURE IF EXISTS edi_load; +DELIMITER $$ +CREATE PROCEDURE edi_load (v_edi INT) +BEGIN + DECLARE v_ref INT; + DECLARE v_buy INT; + DECLARE v_item INT; + DECLARE v_qty INT; + DECLARE v_package INT; + DECLARE v_is_lot BOOLEAN; + + -- Carga los datos necesarios del EKT + + SELECT ref, qty, package INTO v_ref, v_qty, v_package + FROM vn2008.buy_edi e + LEFT JOIN item i ON e.ref = i.id + WHERE e.id = v_edi; + + -- Inserta el cubo si no existe + + IF v_package = 800 + THEN + SET v_package = 800 + v_qty; + + INSERT IGNORE INTO vn2008.Cubos SET + Id_Cubo = v_package, + x = 7200 / v_qty, + y = 1; + ELSE + INSERT IGNORE INTO vn2008.Cubos (Id_Cubo, X, Y, Z) + SELECT bucket_id, ROUND(x_size/10), ROUND(y_size/10), ROUND(z_size/10) + FROM bucket WHERE bucket_id = v_package; + + IF ROW_COUNT() > 0 + THEN + INSERT INTO vn2008.mail SET + `subject` = 'Cubo añadido', + `text` = CONCAT('Se ha añadido el cubo: ', v_package), + `to` = 'ekt@verdnatura.es'; + END IF; + END IF; + + -- Intenta obtener el artículo en base a los atributos holandeses + + INSERT IGNORE INTO item_track SET + item_id = v_ref; + + SELECT c.Id_Compra, c.Id_Article INTO v_buy, v_item + FROM vn2008.buy_edi e + JOIN item_track t ON t.item_id = e.ref + LEFT JOIN vn2008.buy_edi l ON l.ref = e.ref + LEFT JOIN vn2008.Compres c ON c.buy_edi_id = l.id + JOIN vn2008.config cfg + WHERE e.id = v_edi + AND l.id != v_edi + AND c.Id_Article != cfg.generic_item + AND IF(t.s1, l.s1 = e.s1, TRUE) + AND IF(t.s2, l.s2 = e.s2, TRUE) + AND IF(t.s3, l.s3 = e.s3, TRUE) + AND IF(t.s4, l.s4 = e.s4, TRUE) + AND IF(t.s5, l.s5 = e.s5, TRUE) + AND IF(t.s6, l.s6 = e.s6, TRUE) + AND IF(t.kop, l.kop = e.kop, TRUE) + AND IF(t.pac, l.pac = e.pac, TRUE) + AND IF(t.cat, l.cat = e.cat, TRUE) + AND IF(t.ori, l.ori = e.ori, TRUE) + AND IF(t.pro, l.pro = e.pro, TRUE) + AND IF(t.sub, l.sub = e.sub, TRUE) + AND IF(t.package, l.package = e.package, TRUE) + AND c.Id_Article < 170000 + ORDER BY l.now DESC, c.Id_Compra ASC LIMIT 1; + + -- Determina si el articulo se vende por lotes + + IF v_item + THEN + SELECT COUNT(*) > 0 INTO v_is_lot + FROM vn2008.Articles a + LEFT JOIN vn2008.Tipos t ON t.tipo_id = a.tipo_id + WHERE a.Id_Article = v_item + AND t.`transaction`; + + -- Si el articulo se vende por lotes se inserta un nuevo artículo + + IF v_is_lot + THEN + INSERT INTO vn2008.Articles ( + Article + ,Medida + ,Categoria + ,Id_Origen + ,iva_group_id + ,Foto + ,Color + ,Codintrastat + ,tipo_id + ,Tallos + ) + SELECT + i.`name` + ,IFNULL(e.s1, e.pac) + ,e.cat + ,IFNULL(o.id, 17) + ,IFNULL(a.iva_group_id, 1) + ,a.Foto + ,a.Color + ,a.Codintrastat + ,IFNULL(a.tipo_id, 10) + ,IF(a.tipo_id = 15, 0, 1) + FROM vn2008.buy_edi e + LEFT JOIN item i ON i.id = e.ref + LEFT JOIN vn2008.Origen o ON o.Abreviatura = e.ori + LEFT JOIN vn2008.Articles a ON a.Id_Article = v_item + WHERE e.id = v_edi; + + SET v_item = LAST_INSERT_ID(); + END IF; + END IF; + + -- Inserta la compra asociada al EKT + + INSERT INTO vn2008.Compres + ( + Id_Entrada + ,buy_edi_id + ,Costefijo + ,Id_Article + ,Nicho + ,grouping + ,caja + ,Packing + ,Cantidad + ,Productor + ,Etiquetas + ,Id_Cubo + ) + SELECT + cfg.edi_entry + ,v_edi + ,(@t := IF(a.Tallos, a.Tallos, 1)) * e.pri + ,IFNULL(v_item, cfg.generic_item) + ,a.Nicho + ,IFNULL(c.grouping, e.pac) + ,IFNULL(c.caja, TRUE) + ,@pac := e.pac / @t + ,@pac * e.qty + ,s.company_name + ,e.qty + ,IFNULL(c.Id_Cubo, e.package) + FROM vn2008.buy_edi e + LEFT JOIN vn2008.Compres c ON c.Id_Compra = v_buy + LEFT JOIN vn2008.Articles a ON a.Id_Article = c.Id_Article + LEFT JOIN supplier s ON e.pro = s.supplier_id + JOIN vn2008.config cfg + WHERE e.id = v_edi + LIMIT 1; +END$$ +DELIMITER ; diff --git a/rest/edi/plsql/message_new.sql b/rest/edi/plsql/message_new.sql new file mode 100644 index 00000000..0a86ac03 --- /dev/null +++ b/rest/edi/plsql/message_new.sql @@ -0,0 +1,27 @@ +/** + * Registers an email. + * + * @param v_mail_id Message-ID of email + * @param v_sender Origin email id + **/ +USE edi; +DROP PROCEDURE IF EXISTS message_new; +DELIMITER $$ +CREATE PROCEDURE message_new ( + v_mail_id VARCHAR(100) + ,v_sender VARCHAR(150) + ,OUT v_message_id INT +) +BEGIN + DECLARE v_sender_id INT; + + SELECT id INTO v_sender_id FROM mail + WHERE mail = v_sender; + + INSERT IGNORE INTO message SET + sender_id = v_sender_id + ,mail_id = v_mail_id; + + SET v_message_id = LAST_INSERT_ID(); +END$$ +DELIMITER ; diff --git a/rest/edi/schemas/CLOCKT.json b/rest/edi/schemas/CLOCKT.json new file mode 100644 index 00000000..fad8ea24 --- /dev/null +++ b/rest/edi/schemas/CLOCKT.json @@ -0,0 +1,15 @@ +{ + "mainTag": "UNB", + "endTag": "UNZ", + "childs": { + "UNH": { + "endTag": "UNT", + "mandatory": true, + "childs": { + "LIN": { + "mandatory": true + } + } + } + } +} diff --git a/rest/edi/sql/batch-add.sql b/rest/edi/sql/batch-add.sql new file mode 100644 index 00000000..5e8050e2 --- /dev/null +++ b/rest/edi/sql/batch-add.sql @@ -0,0 +1,6 @@ +CALL batch_new ( + @message, #bgm, #aaj, #fec, #hor, #ref, #agj, #cat, #pac, + #sub, #kop, #ptd, #pro, #ori, #ptj, #qty, #pri, #klo, #s1, #s2, #s3, + #s4, #s5, #s6, #k1, #k2, #p1, #p2, #auction, #package +) + diff --git a/rest/edi/sql/bucket.sql b/rest/edi/sql/bucket.sql new file mode 100644 index 00000000..9b2d2dfa --- /dev/null +++ b/rest/edi/sql/bucket.sql @@ -0,0 +1,14 @@ +LOAD DATA LOCAL INFILE #file + INTO TABLE bucket + FIELDS TERMINATED BY ';' + LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7, @col8, @col9, @col10, @col11, @col12) + SET + bucket_id = @col2, + bucket_type_id = @col4, + description = @col5, + x_size = @col6, + y_size = @col7, + z_size = @col8, + entry_date = STR_TO_DATE(@col10, '%Y%m%d'), + expiry_date = IFNULL(NULL,STR_TO_DATE(@col11, '%Y%m%d')), + change_date_time = STR_TO_DATE(@col12, '%Y%m%d%H%i') diff --git a/rest/edi/sql/bucket_type.sql b/rest/edi/sql/bucket_type.sql new file mode 100644 index 00000000..11bcc7f0 --- /dev/null +++ b/rest/edi/sql/bucket_type.sql @@ -0,0 +1,10 @@ +LOAD DATA LOCAL INFILE #file + INTO TABLE bucket_type + FIELDS TERMINATED BY ';' + LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6) + SET + bucket_type_id = @col2, + description = @col3, + entry_date = STR_TO_DATE(@col4, '%Y%m%d'), + expiry_date = IFNULL(NULL,STR_TO_DATE(@col5, '%Y%m%d')), + change_date_time = STR_TO_DATE(@col6, '%Y%m%d%H%i') diff --git a/rest/edi/sql/feature.sql b/rest/edi/sql/feature.sql new file mode 100644 index 00000000..a5d2833c --- /dev/null +++ b/rest/edi/sql/feature.sql @@ -0,0 +1,11 @@ +LOAD DATA LOCAL INFILE #file + INTO TABLE `feature` + FIELDS TERMINATED BY ';' + LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7) + SET + item_id = @col2, + feature_type_id = @col3, + feature_value = @col4, + entry_date = STR_TO_DATE(@col5, '%Y%m%d'), + expiry_date = IFNULL(NULL,STR_TO_DATE(@col6, '%Y%m%d')), + change_date_time = STR_TO_DATE(@col7, '%Y%m%d%H%i') diff --git a/rest/edi/sql/genus.sql b/rest/edi/sql/genus.sql new file mode 100644 index 00000000..0e60fd79 --- /dev/null +++ b/rest/edi/sql/genus.sql @@ -0,0 +1,10 @@ +LOAD DATA LOCAL INFILE #file + INTO TABLE genus + FIELDS TERMINATED BY ';' + LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6) + SET + genus_id = @col2, + latin_genus_name = @col3, + entry_date = STR_TO_DATE(@col4, '%Y%m%d'), + expiry_date = IFNULL(NULL,STR_TO_DATE(@col5, '%Y%m%d')), + change_date_time = STR_TO_DATE(@col6, '%Y%m%d%H%i') diff --git a/rest/edi/sql/item.sql b/rest/edi/sql/item.sql new file mode 100644 index 00000000..1c348439 --- /dev/null +++ b/rest/edi/sql/item.sql @@ -0,0 +1,13 @@ +LOAD DATA LOCAL INFILE #file + INTO TABLE item + FIELDS TERMINATED BY ';' + LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7, @col8, @col9, @col10, @col11, @col12) + SET + id = @col2, + product_name = @col4, + name = @col5, + plant_id = @col7, + group_id = @col9, + entry_date = STR_TO_DATE(@col10, '%Y%m%d'), + expiry_date = IFNULL(NULL,STR_TO_DATE(@col11, '%Y%m%d')), + change_date_time = STR_TO_DATE(@col12, '%Y%m%d%H%i') diff --git a/rest/edi/sql/item_feature.sql b/rest/edi/sql/item_feature.sql new file mode 100644 index 00000000..81ddbc73 --- /dev/null +++ b/rest/edi/sql/item_feature.sql @@ -0,0 +1,12 @@ +LOAD DATA LOCAL INFILE #file + INTO TABLE `item_feature` + FIELDS TERMINATED BY ';' + LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7, @col8) + SET + item_id = @col2, + feature = @col3, + regulation_type = @col4, + presentation_order = @col5, + entry_date = STR_TO_DATE(@col6, '%Y%m%d'), + expiry_date = IFNULL(NULL,STR_TO_DATE(@col7, '%Y%m%d')), + change_date_time = STR_TO_DATE(@col8, '%Y%m%d%H%i') diff --git a/rest/edi/sql/item_group.sql b/rest/edi/sql/item_group.sql new file mode 100644 index 00000000..cbdc1328 --- /dev/null +++ b/rest/edi/sql/item_group.sql @@ -0,0 +1,10 @@ +LOAD DATA LOCAL INFILE #file + INTO TABLE item_group + FIELDS TERMINATED BY ';' + LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6) + SET + group_code = @col2, + dutch_group_description = @col3, + entry_date = STR_TO_DATE(@col4, '%Y%m%d'), + expiry_date = IFNULL(NULL,STR_TO_DATE(@col5, '%Y%m%d')), + change_date_time = STR_TO_DATE(@col6, '%Y%m%d%H%i') diff --git a/rest/edi/sql/plant.sql b/rest/edi/sql/plant.sql new file mode 100644 index 00000000..ba969afa --- /dev/null +++ b/rest/edi/sql/plant.sql @@ -0,0 +1,11 @@ +LOAD DATA LOCAL INFILE #file + INTO TABLE plant + FIELDS TERMINATED BY ';' + LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7, @col8, @col9) + SET + plant_id = @col3, + genus_id = @col4, + specie_id = @col5, + entry_date = STR_TO_DATE(@col7, '%Y%m%d'), + expiry_date = IFNULL(NULL,STR_TO_DATE(@col8, '%Y%m%d')), + change_date_time = STR_TO_DATE(@col9, '%Y%m%d%H%i') diff --git a/rest/edi/sql/specie.sql b/rest/edi/sql/specie.sql new file mode 100644 index 00000000..883d97b7 --- /dev/null +++ b/rest/edi/sql/specie.sql @@ -0,0 +1,11 @@ +LOAD DATA LOCAL INFILE #file + INTO TABLE specie + FIELDS TERMINATED BY ';' + LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7) + SET + specie_id = @col2, + genus_id = @col3, + latin_species_name = @col4, + entry_date = STR_TO_DATE(@col5, '%Y%m%d'), + expiry_date = IFNULL(NULL,STR_TO_DATE(@col6, '%Y%m%d')), + change_date_time = STR_TO_DATE(@col7, '%Y%m%d%H%i') diff --git a/rest/edi/sql/supplier.sql b/rest/edi/sql/supplier.sql new file mode 100644 index 00000000..93c82929 --- /dev/null +++ b/rest/edi/sql/supplier.sql @@ -0,0 +1,10 @@ +LOAD DATA LOCAL INFILE #file + INTO TABLE supplier + FIELDS TERMINATED BY ';' + LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7, @col8, @col9, @col10, @col11, @col12, @col13, @col14, @col15, @col16, @col17, @col18, @col19, @col20) + SET + supplier_id = @col4, + company_name = @col3, + entry_date = STR_TO_DATE(@col9, '%Y%m%d'), + expiry_date = IFNULL(NULL,STR_TO_DATE(@col10, '%Y%m%d')), + change_date_time = STR_TO_DATE(@col11, '%Y%m%d%H%i') diff --git a/rest/edi/sql/type.sql b/rest/edi/sql/type.sql new file mode 100644 index 00000000..77c0883d --- /dev/null +++ b/rest/edi/sql/type.sql @@ -0,0 +1,11 @@ +LOAD DATA LOCAL INFILE #file + INTO TABLE `type` + FIELDS TERMINATED BY ';' + LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7) + SET + type_id = @col2, + type_group_id = @col3, + description = @col4, + entry_date = STR_TO_DATE(@col5, '%Y%m%d'), + expiry_date = IFNULL(NULL,STR_TO_DATE(@col6, '%Y%m%d')), + change_date_time = STR_TO_DATE(@col7, '%Y%m%d%H%i') diff --git a/rest/edi/sql/value.sql b/rest/edi/sql/value.sql new file mode 100644 index 00000000..288b8c10 --- /dev/null +++ b/rest/edi/sql/value.sql @@ -0,0 +1,11 @@ +LOAD DATA LOCAL INFILE #file + INTO TABLE `value` + FIELDS TERMINATED BY ';' + LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7) + SET + type_id = @col2, + type_value = @col3, + type_description = @col4, + entry_date = STR_TO_DATE(@col5, '%Y%m%d'), + expiry_date = IFNULL(NULL,STR_TO_DATE(@col6, '%Y%m%d')), + change_date_time = STR_TO_DATE(@col7, '%Y%m%d%H%i') diff --git a/rest/edi/update.php b/rest/edi/update.php new file mode 100644 index 00000000..aeec615f --- /dev/null +++ b/rest/edi/update.php @@ -0,0 +1,119 @@ +getSysConn (); + $db->selectDb ('edi'); + //$db->options (MYSQLI_OPT_LOCAL_INFILE, TRUE); + + $tmpDir = '/tmp/floricode'; + + // Establece una conexión FTP + + $ftpConf = $db->getRow ('SELECT host, user, password FROM ftp_config'); + $ftpConn = ftp_connect ($ftpConf['host']); + + if (!$ftpConn) + throw new Exception ('Can not connect to '. $ftpConf['host']); + + if (!ftp_login ($ftpConn, $ftpConf['user'], $ftpConf['password'])) + throw new Exception ('Can not login to '. $ftpConf['user'] .'@'. $ftpConf['host']); + + // Obtiene el listado de tablas a actualizar + + set_time_limit (0); + + $res = $db->query ( + 'SELECT file_name, to_table, file, updated FROM file_config'); + + $dwFiles = []; + + if (!file_exists ($tmpDir)) + mkdir ($tmpDir); + + while ($row = $res->fetch_assoc ()) + try { + $file = $row['file']; + $table = $row['to_table']; + $baseName = $row['file_name']; + + if ($row['updated']) + $updated = DateTime::createFromFormat ('Y-m-d', $row['updated']); + else + $updated = NULL; + + $remoteFile = "codes/$file.ZIP"; + $zipFile = "$tmpDir/$file.zip"; + $ucDir = "$tmpDir/$file"; + + // Intenta descargar y descomprimir el fichero con los datos + + if (!isset ($dwFiles[$file])) + { + $dwFiles[$file] = TRUE; + + if (!ftp_get ($ftpConn, $zipFile, $remoteFile, FTP_BINARY)) + throw new Exception ("Error downloading $remoteFile to $zipFile"); + + $zip = new ZipArchive; + + if ($zip->open ($zipFile) !== TRUE) + throw new Exception ("Can not open $zipFile"); + + @mkdir ($ucDir, 0774, TRUE); + + if (!$zip->extractTo ($ucDir)) + throw new Exception ("Can not uncompress file $zipFile"); + + $zip->close(); + unlink ($zipFile); + } + + foreach (glob ("$ucDir/$baseName*.txt") as $fileName) + break; + + if (!$fileName) + throw new Exception ("Import file for table $table does not exist"); + + // Si los datos están actualizados omite la tabla + + $lastUpdated = substr ($fileName, -10, 6); + $lastUpdated = DateTime::createFromFormat ('dmy', $lastUpdated); + + if ($updated && $lastUpdated <= $updated) + continue; + + // Actualiza los datos de la tabla + + $importQuery = $db->loadFromFile ("sql/$table", ['file' => $fileName]); + + $db->multiQuery ( + "START TRANSACTION; + DELETE FROM $table; + $importQuery; + UPDATE file_config SET updated = # WHERE file_name = #; + COMMIT;", + [$lastUpdated, $baseName] + ); + + do { + $db->storeResult (); + } + while ($db->moreResults () && $db->nextResult ()); + } + catch (Exception $e) + { + $db->query ('ROLLBACK'); + error_log ($e->getMessage ()); + } + + shell_exec ("rm -R $tmpDir"); + ftp_close ($ftpConn); + } +} + +?> diff --git a/rest/image/resize.php b/rest/image/resize.php index 985c798c..ea42c18c 100644 --- a/rest/image/resize.php +++ b/rest/image/resize.php @@ -64,7 +64,7 @@ class Resize extends Vn\Lib\Method catch (\Exception $e) {} } - echo "$count files resized"; + echo "$count files resized.\n"; } } diff --git a/rest/image/sync.php b/rest/image/sync.php index 78c525d7..352c69a4 100644 --- a/rest/image/sync.php +++ b/rest/image/sync.php @@ -86,7 +86,7 @@ class Sync extends Vn\Lib\Method $this->cleanImages ($schema, $size, $map); } - echo "Syncronization finished"; + echo "Syncronization finished.\n"; } function cleanImages ($schema, $size, &$map) diff --git a/rest/misc/exchange-rate.php b/rest/misc/exchange-rate.php new file mode 100755 index 00000000..f2fcab60 --- /dev/null +++ b/rest/misc/exchange-rate.php @@ -0,0 +1,54 @@ + + **/ +class ExchangeRate extends Vn\Lib\Method +{ + function run () + { + $db = $this->getSysConn (); + + // 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->query ( + 'REPLACE INTO reference_rate (moneda_id, date, rate) + VALUES (2, TIMESTAMPADD(DAY, 1, #date), #rate)', + $params + ); + } + } + + $db->queryFromFile (__DIR__.'/exrate-add'); + } +} + +?> diff --git a/rest/misc/exrate-add.sql b/rest/misc/exrate-add.sql new file mode 100644 index 00000000..dec99c25 --- /dev/null +++ b/rest/misc/exrate-add.sql @@ -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, -1, CURDATE()) diff --git a/rest/misc/mail.php b/rest/misc/mail.php new file mode 100755 index 00000000..a54911d3 --- /dev/null +++ b/rest/misc/mail.php @@ -0,0 +1,91 @@ +getSysConn (); + $db->query ('START TRANSACTION'); + + $conf = $db->getRow ( + 'SELECT host, port, secure, sender, sender_name, user, password + FROM hedera.mail_config' + ); + $res = $db->query ( + 'SELECT * FROM mail WHERE sent = 0 ORDER BY DATE_ODBC DESC + LIMIT 20 FOR UPDATE'); + + while ($row = $res->fetch_assoc ()) + { + $sent = 1; + $status = 'OK'; + + try { + if (!preg_match ('/^[\w\._%-]+@[\w\.-]+\.[A-Za-z]{2,4}$/', $row['to'])) + throw new Exception ('Destination mail has invalid sintax'); + + $mail = new PHPMailer (); + $mail->isSMTP (); + $mail->Host = $conf['host']; + + if (!empty ($conf['user'])) + { + $mail->SMTPAuth = TRUE; + $mail->Username = $conf['user']; + $mail->Password = base64_decode ($conf['password']); + } + else + $mail->SMTPAuth = FALSE; + + if ($conf['secure']) + { + $mail->SMTPSecure = 'ssl'; + $mail->Port = 465; + } + + $mail->setFrom ($conf['sender'], $conf['sender_name']); + $mail->AddReplyTo ($row['reply_to'], 'Att. Cliente'); + + if (strpos ($row['to'], ',')) + $mailList = explode (',', $row['to']); + else + $mailList = explode (';', $row['to']); + + foreach ($mailList as $mailTo) + $mail->AddAddress ($mailTo); + + $mail->Subject = $row['subject']; + $mail->Body = ' '. $row['text']; + $mail->CharSet = 'UTF-8'; + + if (!empty ($row['path'])) + { + $attachment = '/mnt/storage/pdfs/'. $row['path']; + + if (file_exists ($attachment)) + $mail->AddAttachment ($attachment, ''); + else + throw new Exception ('Attachment file could not be found: '. $attachment); + } + + if (!$mail->Send ()) + throw new Exception ('Send error: '.$mail->ErrorInfo); + } + catch (Exception $e) + { + $sent = 2; + $status = $e->getMessage (); + } + + $db->query ('UPDATE mail SET sent = #, error = # WHERE id = #', + [$sent, $status, $row['id']]); + } + + $db->query ('COMMIT'); + } +} + +?> diff --git a/rest/tpv/confirm-mail.php b/rest/tpv/confirm-mail.php index c9dcb54c..744ee342 100644 --- a/rest/tpv/confirm-mail.php +++ b/rest/tpv/confirm-mail.php @@ -31,6 +31,7 @@ class ConfirmMail extends Vn\Lib\Method // Fetchs and confirms new transaction mails + $count = 0; $inbox = imap_search ($imap, 'ALL'); if ($inbox) @@ -50,6 +51,8 @@ class ConfirmMail extends Vn\Lib\Method // Confirms the transaction + $success = FALSE; + try { $success = Tpv::confirm ($db, $params); } @@ -67,13 +70,15 @@ class ConfirmMail extends Vn\Lib\Method if (!imap_mail_move ($imap, $msg, "INBOX.$folder")) trigger_error (imap_last_error (), E_USER_WARNING); + + $count++; } imap_expunge ($imap); // Cleans the old mails - $deleted = NULL; + $deleted = 0; if (rand (1, 20) == 1) { @@ -82,7 +87,6 @@ class ConfirmMail extends Vn\Lib\Method ,$imapConf['error_folder'] ); - $deleted = 0; $date = new \DateTime (NULL); $date->sub (new \DateInterval ($imapConf['clean_period'])); $filter = sprintf ('BEFORE "%s"', $date->format('D, j M Y')); @@ -99,7 +103,7 @@ class ConfirmMail extends Vn\Lib\Method } } - echo "TPV: $count mails processed, $deleted mails deleted"; + echo "$count mails processed, $deleted mails deleted.\n"; } } diff --git a/vn/web/app.php b/vn/web/app.php old mode 100755 new mode 100644 index a4381718..1fb29480 --- a/vn/web/app.php +++ b/vn/web/app.php @@ -3,135 +3,52 @@ namespace Vn\Web; require_once ('vn/lib/app.php'); -require_once ('vn/lib/util.php'); - -use Vn\Lib; -use Vn\Lib\Locale; -use Vn\Db\Conn; - -/** - * Thrown when user credentials could not be fetched. - **/ -class SessionExpiredException extends Lib\UserException {} - -/** - * Thrown when user credentials are invalid. - **/ -class BadLoginException extends Lib\UserException {} - -/** - * Thrown when client version is outdated. - **/ -class OutdatedVersionException extends Lib\UserException {} /** * Main class for web applications. + * + * Format for $_REQUEST['srv'] variable: + * - [serviceName]:[requestDir]/[requestFile] **/ -abstract class App extends Lib\App +class App extends \Vn\Lib\App { - protected $conn = NULL; + private $allowedServices = + [ + 'html', + 'rest', + 'json' + ]; - /** - * Starts the user session. - **/ - function startSession () + function run () { - if ($this->isHttps ()) - ini_set ('session.cookie_secure', TRUE); + $this->init (); - ini_set ('session.hash_function', 'sha512'); - session_start (); - - // Setting the locale + $srv = empty ($_REQUEST['srv']) ? '' : $_REQUEST['srv']; + $explode = explode (':', $srv, 2); - if (isset ($_SERVER['HTTP_ACCEPT_LANGUAGE'])) - if (!isset ($_SESSION['http_language']) - || $_SESSION['http_language'] != $_SERVER['HTTP_ACCEPT_LANGUAGE']) + if (count ($explode) > 0) + $_REQUEST['service'] = $explode[0]; + if (count ($explode) > 1) + $_REQUEST['method'] = $explode[1]; + + $service = empty ($_REQUEST['service']) ? 'html' : $_REQUEST['service']; + + if (in_array ($service, $this->allowedServices, TRUE)) { - $_SESSION['http_language'] = $_SERVER['HTTP_ACCEPT_LANGUAGE']; - $regexp = '/([a-z]{1,4})(?:-[a-z]{1,4})?\s*(?:;\s*q\s*=\s*(?:1|0\.[0-9]+))?,?/i'; + $includeFile = __DIR__."/$service-service.php"; + require_once ($includeFile); - preg_match_all ($regexp, $_SERVER['HTTP_ACCEPT_LANGUAGE'], $languages); - - foreach ($languages[1] as $lang) - if (stream_resolve_include_path ("locale/$lang")) - { - $_SESSION['lang'] = $lang; - break; - } - } - - if (!isset ($_SESSION['lang'])) - $_SESSION['lang'] = NULL; - - Locale::set ($_SESSION['lang']); - - // Registering the visit - - if (!isset ($_COOKIE['PHPSESSID']) - || isset ($_SESSION['access']) - || isset ($_SESSION['skipVisit'])) - return; - - $agent = $_SERVER['HTTP_USER_AGENT']; - $browser = get_browser ($agent, TRUE); - - if (isset ($browser['crawler']) && $browser['crawler']) - { - $_SESSION['skipVisit'] = TRUE; - return; - } - - if (isset ($_SERVER['REMOTE_ADDR'])) - $ip = ip2long ($_SERVER['REMOTE_ADDR']); - - $sysConn = $this->getSysConn (); - $row = $sysConn->getRow ( - 'CALL visit_register (#, #, #, #, #, #, #, #, #)', - [ - nullIf ($_COOKIE, 'vn_visit') - ,nullIf ($browser, 'platform') - ,nullIf ($browser, 'browser') - ,nullIf ($browser, 'version') - ,nullIf ($browser, 'javascript') - ,nullIf ($browser, 'cookies') - ,isset ($agent) ? $agent : NULL - ,isset ($ip) && $ip ? $ip : NULL - ,nullIf ($_SERVER, 'HTTP_REFERER') - ] - ); - - if (isset ($row['access'])) - { - setcookie ('vn_visit', $row['visit'], time () + 31536000); // 1 Year - $_SESSION['access'] = $row['access']; + $className = __NAMESPACE__ .'\\'. hyphenToCamelCase ($service, TRUE) .'Service'; + $service = new $className ($this); + $service->run (); } else - $_SESSION['skipVisit'] = TRUE; + http_response_code (400); } /** - * Checks if the HTTP connection is secure. - * - * @return boolean Return %TRUE if its secure, %FALSE otherwise - **/ - function isHttps () - { - return isset ($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on'; - } - - /** - * Obtains the application version number. It is based on de last - * modification date of the main script. - **/ - function getVersion () - { - return (int) strftime ('%G%m%d%H%M%S', - filectime (__FILE__ /* $_SERVER['SCRIPT_FILENAME'] */)); - } - - /** - * Gets the configuration file name. + * Gets the configuration file name associated to the current vhost + * or the default config file if isn't defined a file for the vhost. **/ function getConfigFile () { diff --git a/vn/web/html-app.php b/vn/web/html-service.php similarity index 90% rename from vn/web/html-app.php rename to vn/web/html-service.php index b3aa0c2e..44c97972 100644 --- a/vn/web/html-app.php +++ b/vn/web/html-service.php @@ -2,21 +2,18 @@ namespace Vn\Web; -require_once (__DIR__.'/app.php'); -require_once ('vn/lib/util.php'); -require_once ('vn/lib/method.php'); +require_once (__DIR__.'/service.php'); use Vn\Lib\Locale; /** * Base class for services that sends response as HTML format. **/ -class HtmlApp extends App +class HtmlService extends Service { function run () { - $this->init (); - $db = $this->getSysConn (); + $db = $this->app->getSysConn (); if (!$this->isHttps () && $db->getValue ('SELECT https FROM config')) @@ -29,8 +26,8 @@ class HtmlApp extends App // Getting the requested page - if (!empty ($_GET['page']) && isHyphen ($_GET['page'])) - $page = $_GET['page']; + if (!empty ($_REQUEST['method']) && isHyphen ($_REQUEST['method'])) + $page = $_REQUEST['method']; else $page = 'main'; @@ -77,7 +74,7 @@ class HtmlApp extends App // Loading the requested page - $basePath = "{$this->methodDir}/$page"; + $basePath = "./html/$page"; if (file_exists ($basePath)) { diff --git a/vn/web/json-app.php b/vn/web/json-service.php similarity index 92% rename from vn/web/json-app.php rename to vn/web/json-service.php index 771c90e2..533cb299 100644 --- a/vn/web/json-app.php +++ b/vn/web/json-service.php @@ -2,7 +2,7 @@ namespace Vn\Web; -require_once (__DIR__.'/rest-app.php'); +require_once (__DIR__.'/rest-service.php'); require_once (__DIR__.'/json-request.php'); require_once (__DIR__.'/json-reply.php'); @@ -11,7 +11,7 @@ use Vn\Lib; /** * Base class for JSON application. **/ -class JsonApp extends RestApp +class JsonService extends RestService { private $warnings = NULL; @@ -21,7 +21,6 @@ class JsonApp extends RestApp set_error_handler ([$this, 'errorHandler'], E_ALL); set_exception_handler ([$this, 'exceptionHandler']); - $this->init (); $this->startSession (); // Checks the client version @@ -33,7 +32,8 @@ class JsonApp extends RestApp && $clientVersion < $this->getVersion ()) throw new OutdatedVersionException (); - $method = $this->loadMethod ($_REQUEST['method']); + $method = $this->app->loadMethod ( + $_REQUEST['method'], __NAMESPACE__.'\JsonRequest', './rest'); $json = $method->run (); $this->replyJson ($json); } diff --git a/vn/web/rest-app.php b/vn/web/rest-service.php similarity index 93% rename from vn/web/rest-app.php rename to vn/web/rest-service.php index da7c9f67..fff9c33f 100644 --- a/vn/web/rest-app.php +++ b/vn/web/rest-service.php @@ -2,7 +2,7 @@ namespace Vn\Web; -require_once (__DIR__.'/app.php'); +require_once (__DIR__.'/service.php'); require_once (__DIR__.'/rest-request.php'); use Vn\Lib; @@ -10,7 +10,7 @@ use Vn\Lib; /** * Base class for REST application. **/ -class RestApp extends App +class RestService extends Service { function run () { @@ -18,10 +18,10 @@ class RestApp extends App set_error_handler ([$this, 'errorHandler'], E_ALL); set_exception_handler ([$this, 'exceptionHandler']); - $this->init (); $this->startSession (); - $method = $this->loadMethod ($_REQUEST['method']); + $method = $this->app->loadMethod ( + $_REQUEST['method'], __NAMESPACE__.'\RestRequest', './rest'); $method->run (); } @@ -47,7 +47,7 @@ class RestApp extends App if (isset ($_POST['guest'])) { - $sysConn = $this->getSysConn (); + $sysConn = $this->app->getSysConn (); $row = $sysConn->getRow ( 'SELECT guest_user, guest_pass FROM config'); @@ -83,7 +83,7 @@ class RestApp extends App throw new SessionExpiredException (); try { - $db = $this->createConnection ($user, $password); + $db = $this->app->createConnection ($user, $password); $db->query ('CALL user_session_start (#)', [session_id ()]); $this->conn = $db; diff --git a/vn/web/service.php b/vn/web/service.php new file mode 100755 index 00000000..f90036df --- /dev/null +++ b/vn/web/service.php @@ -0,0 +1,139 @@ +app = $app; + } + + /** + * Starts the user session. + **/ + function startSession () + { + if ($this->isHttps ()) + ini_set ('session.cookie_secure', TRUE); + + ini_set ('session.hash_function', 'sha512'); + session_start (); + + // Setting the locale + + if (isset ($_SERVER['HTTP_ACCEPT_LANGUAGE'])) + if (!isset ($_SESSION['http_language']) + || $_SESSION['http_language'] != $_SERVER['HTTP_ACCEPT_LANGUAGE']) + { + $_SESSION['http_language'] = $_SERVER['HTTP_ACCEPT_LANGUAGE']; + $regexp = '/([a-z]{1,4})(?:-[a-z]{1,4})?\s*(?:;\s*q\s*=\s*(?:1|0\.[0-9]+))?,?/i'; + + preg_match_all ($regexp, $_SERVER['HTTP_ACCEPT_LANGUAGE'], $languages); + + foreach ($languages[1] as $lang) + if (stream_resolve_include_path ("locale/$lang")) + { + $_SESSION['lang'] = $lang; + break; + } + } + + if (!isset ($_SESSION['lang'])) + $_SESSION['lang'] = NULL; + + Locale::set ($_SESSION['lang']); + + // Registering the visit + + if (!isset ($_COOKIE['PHPSESSID']) + || isset ($_SESSION['access']) + || isset ($_SESSION['skipVisit'])) + return; + + $agent = $_SERVER['HTTP_USER_AGENT']; + $browser = get_browser ($agent, TRUE); + + if (isset ($browser['crawler']) && $browser['crawler']) + { + $_SESSION['skipVisit'] = TRUE; + return; + } + + if (isset ($_SERVER['REMOTE_ADDR'])) + $ip = ip2long ($_SERVER['REMOTE_ADDR']); + + $db = $this->app->getSysConn (); + $row = $db->getRow ( + 'CALL visit_register (#, #, #, #, #, #, #, #, #)', + [ + nullIf ($_COOKIE, 'vn_visit') + ,nullIf ($browser, 'platform') + ,nullIf ($browser, 'browser') + ,nullIf ($browser, 'version') + ,nullIf ($browser, 'javascript') + ,nullIf ($browser, 'cookies') + ,isset ($agent) ? $agent : NULL + ,isset ($ip) && $ip ? $ip : NULL + ,nullIf ($_SERVER, 'HTTP_REFERER') + ] + ); + + if (isset ($row['access'])) + { + setcookie ('vn_visit', $row['visit'], time () + 31536000); // 1 Year + $_SESSION['access'] = $row['access']; + } + else + $_SESSION['skipVisit'] = TRUE; + } + + /** + * Checks if the HTTP connection is secure. + * + * @return boolean Return %TRUE if its secure, %FALSE otherwise + **/ + function isHttps () + { + return isset ($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on'; + } + + /** + * Obtains the application version number. It is based on de last + * modification date of the main script. + **/ + function getVersion () + { + return (int) strftime ('%G%m%d%H%M%S', + filectime (__FILE__ /* $_SERVER['SCRIPT_FILENAME'] */)); + } +} + +?>