fix: migrate pending orders #121

Merged
jsegarra merged 7 commits from ldragan/hedera-web:taro/pending-orders into beta 2025-03-27 05:15:04 +00:00
3 changed files with 71 additions and 26 deletions

View File

@ -1,2 +1,5 @@
debian
node_modules
node_modules
.quasar
build
.vscode

View File

@ -1,5 +1,5 @@
<script setup>
import { ref, inject, onMounted } from 'vue';
import { ref, inject } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router';
@ -11,8 +11,10 @@ import { useVnConfirm } from 'src/composables/useVnConfirm.js';
import useNotify from 'src/composables/useNotify.js';
import { useAppStore } from 'stores/app';
import { storeToRefs } from 'pinia';
import { onUserId } from 'src/utils/onUserId';
const jApi = inject('jApi');
const api = inject('api');
const { t } = useI18n();
const { openConfirmationModal } = useVnConfirm();
const { notify } = useNotify();
@ -23,18 +25,48 @@ const router = useRouter();
const loading = ref(false);
const orders = ref([]);
const getOrders = async () => {
const getOrders = async (clientFk) => {
try {
loading.value = true;
orders.value = await jApi.query(
`SELECT o.id, o.sent, o.deliveryMethodFk, o.taxableBase,
a.nickname, am.description agency
FROM myOrder o
JOIN myAddress a ON a.id = o.addressFk
JOIN vn.agencyMode am ON am.id = o.agencyModeFk
WHERE NOT o.isConfirmed
ORDER BY o.sent DESC`
);
const filter = {
where: {
clientFk,
isConfirmed: false,

a nivel de BD funciona bien, pero como lo consultamos desde el front, mejor aplicamos del standard Booleano true/false

a nivel de BD funciona bien, pero como lo consultamos desde el front, mejor aplicamos del standard Booleano true/false
source_app: 'WEB',
},
include: [
jsegarra marked this conversation as resolved
Review

haces para que te traiga el objeto de address?
Quiero decir, la relacion ya está con clave primaria, por tanto no haria falta ponerlo en el where

haces para que te traiga el objeto de address? Quiero decir, la relacion ya está con clave primaria, por tanto no haria falta ponerlo en el where
Review

Coincido, pero así estaba la query y preferí no cambiarla. (La view myAddress tiene incluido el filtro de clientFk).

Por lo que veo en order.json, el join se hace via el address_id, y no hay una garantía real y determinística de que el address.clientFk coincida con el order.clientFk— ello depende de que nunca se haga un insert o update "incorrecto" en algún lugar del código, para alguna defición de "correcto".

Yo considero que remover esta parte del where sería un refactor, y no es estrictamente parte de la migración. Estoy a favor, pero suelo preferir el camino conservador, y encarar los dos cambios en 2 PRs separados, para simplificar el debugging en el remoto caso de que ocurra un error inesperado por alguna incongruencia en la data.

Por otro lado, lo más probable es que remover esta condición no cause ningún problema, y, aún si lo hiciera, el impacto debería ser mínimo, inmediatamente observable y fácil de resolver.

Si estás a favor de quitar el 'address.clientFk': clientFk,, entonces yo también :)

Coincido, pero así estaba la query y preferí no cambiarla. (La view `myAddress` tiene incluido el filtro de `clientFk`). Por lo que veo en `order.json`, el `join` se hace via el `address_id`, y no hay una garantía real y determinística de que el `address.clientFk` coincida con el `order.clientFk`— ello depende de que nunca se haga un `insert` o `update` "incorrecto" en algún lugar del código, para alguna defición de "correcto". Yo considero que remover esta parte del `where` sería un refactor, y no es estrictamente parte de la migración. Estoy a favor, pero suelo preferir el camino conservador, y encarar los dos cambios en 2 PRs separados, para simplificar el debugging en el remoto caso de que ocurra un error inesperado por alguna incongruencia en la data. Por otro lado, lo más probable es que remover esta condición no cause ningún problema, y, aún si lo hiciera, el impacto debería ser mínimo, inmediatamente observable y fácil de resolver. Si estás a favor de quitar el `'address.clientFk': clientFk,`, entonces yo también :)
Review

Dale con todo y quitemosla

Dale con todo y quitemosla
Review

y validamos con los tests

y validamos con los tests
Review

Awesome. Hecho :)

Awesome. Hecho :)
{
relation: 'address',
Review

este source_app no lo veo en la query origen

este source_app no lo veo en la query origen
Review

La query original se hacía contra myOrder , que es una view:

MariaDB [(none)]> show create view `hedera`.`myOrder`;
*************************** 1. row ***************************
                View: myOrder
         Create View: CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `hedera`.`myOrder` AS select `o`.`id` AS `id`,`o`.`date_send` AS `sent`,`o`.`customer_id` AS `clientFk`,`o`.`delivery_method_id` AS `deliveryMethodFk`,`o`.`agency_id` AS `agencyModeFk`,`o`.`address_id` AS `addressFk`,`o`.`company_id` AS `companyFk`,`o`.`note` AS `notes`,`o`.`source_app` AS `sourceApp`,`o`.`confirmed` AS `isConfirmed`,`o`.`date_make` AS `created`,`o`.`first_row_stamp` AS `firstRowStamp`,`o`.`confirm_date` AS `confirmed`,`o`.`taxableBase` AS `taxableBase`,`o`.`tax` AS `tax`,`o`.`total` AS `total` from `hedera`.`order` `o` where `o`.`customer_id` = `account`.`myUser_getId`() and `o`.`source_app` = 'WEB' and `o`.`confirmed` = 0 WITH CASCADED CHECK OPTION
character_set_client: utf8mb4
collation_connection: utf8mb4_unicode_ci
1 row in set (0.156 sec)

La view incluye el source_app y otros filtros:

 where `o`.`customer_id` = `account`.`myUser_getId`() and `o`.`source_app` = 'WEB' and `o`.`confirmed` = 0
La query original se hacía contra `myOrder` , que es una view: ``` MariaDB [(none)]> show create view `hedera`.`myOrder`; *************************** 1. row *************************** View: myOrder Create View: CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `hedera`.`myOrder` AS select `o`.`id` AS `id`,`o`.`date_send` AS `sent`,`o`.`customer_id` AS `clientFk`,`o`.`delivery_method_id` AS `deliveryMethodFk`,`o`.`agency_id` AS `agencyModeFk`,`o`.`address_id` AS `addressFk`,`o`.`company_id` AS `companyFk`,`o`.`note` AS `notes`,`o`.`source_app` AS `sourceApp`,`o`.`confirmed` AS `isConfirmed`,`o`.`date_make` AS `created`,`o`.`first_row_stamp` AS `firstRowStamp`,`o`.`confirm_date` AS `confirmed`,`o`.`taxableBase` AS `taxableBase`,`o`.`tax` AS `tax`,`o`.`total` AS `total` from `hedera`.`order` `o` where `o`.`customer_id` = `account`.`myUser_getId`() and `o`.`source_app` = 'WEB' and `o`.`confirmed` = 0 WITH CASCADED CHECK OPTION character_set_client: utf8mb4 collation_connection: utf8mb4_unicode_ci 1 row in set (0.156 sec) ``` La view incluye el `source_app` y otros filtros: ``` where `o`.`customer_id` = `account`.`myUser_getId`() and `o`.`source_app` = 'WEB' and `o`.`confirmed` = 0 ```
Review

Comentado por @alexm
Puedes definirte una vista como un modelo normal
modules/worker/back/models/worker-department.json por ejemplo, es una vista

Comentado por @alexm Puedes definirte una vista como un modelo normal modules/worker/back/models/worker-department.json por ejemplo, es una vista
Review

For the record, esto lo charlamos en la daily, y quedamos en ver si al equipo le parece bien dejar esto así, o hacer un cambio mayor, para agregar un modelo loopback sobre una view.

Mi argumento a favor de dejar esto así es que, al largo plazo, lo mejor sería directamente ya no usar las views, y usar completamente lo que ofrece loopback (hacerlo "the loopback way", digamos).

Por otro lado, la view incluye la llamada al myUser_getId(), el antiguo método de autorización, que, considero, deberíamos apuntar a eliminar completamente. Usar la view implica usar una transacción de la DB y ejecutar un 'CALL account.myUser_loginWithName((SELECT name FROM account.user WHERE id = ?))',, como lo hace VnModel.rawSql. Perdemos casi todos los beneficios de loopback.

For the record, esto lo charlamos en la daily, y quedamos en ver si al equipo le parece bien dejar esto así, o hacer un cambio mayor, para agregar un modelo loopback sobre una view. Mi argumento a favor de dejar esto así es que, al largo plazo, lo mejor sería directamente ya no usar las views, y usar completamente lo que ofrece loopback (hacerlo "the loopback way", digamos). Por otro lado, la view incluye la llamada al `myUser_getId()`, el antiguo método de autorización, que, considero, deberíamos apuntar a eliminar completamente. Usar la view implica usar una transacción de la DB y ejecutar un `'CALL account.myUser_loginWithName((SELECT name FROM account.user WHERE id = ?))',`, como lo hace `VnModel.rawSql`. Perdemos casi todos los beneficios de loopback.
scope: {
fields: ['nickname', 'city'],
}
},
{
relation: 'agencyMode',
scope: {
fields: ['description'],
}
},
],
fields: [
'id',
'landed',
'delivery_method_id',
'taxableBase',
'addressFk',
'agencyModeFk'
]
};
const { data: salixOrders } = await api.get('Orders', {
params: {
filter: JSON.stringify(filter)
}
});
orders.value = salixOrders;
loading.value = false;
} catch (error) {
console.error('Error getting orders:', error);
@ -43,14 +75,7 @@ const getOrders = async () => {
const removeOrder = async (id, index) => {
try {
await jApi.execQuery(
`START TRANSACTION;
DELETE FROM hedera.myOrder WHERE ((id = #id));
COMMIT`,
{
id
}
);
await api.delete(`Orders/${id}`);
orders.value.splice(index, 1);
Review

Lo veo bien, pero cuando tengamos un respiro miraria de hacer algo para que refresque haciendo un refetch por ejemplo. https://gitea.verdnatura.es/verdnatura/salix-front/src/branch/dev/src/components/VnTable/VnTable.vue#L311

Lo veo bien, pero cuando tengamos un respiro miraria de hacer algo para que refresque haciendo un refetch por ejemplo. https://gitea.verdnatura.es/verdnatura/salix-front/src/branch/dev/src/components/VnTable/VnTable.vue#L311
notify(t('dataSaved'), 'positive');
} catch (error) {
@ -63,9 +88,8 @@ const loadOrder = orderId => {
router.push({ name: 'catalog' });
};
onMounted(async () => {
getOrders();
});
onUserId(getOrders);
</script>
<template>
@ -93,11 +117,11 @@ onMounted(async () => {
>
<template #content>
<QItemLabel class="text-bold q-mb-sm">
{{ formatDateTitle(order.sent) }}
{{ formatDateTitle(order.landed) }}
</QItemLabel>
<QItemLabel> #{{ order.id }} </QItemLabel>
<QItemLabel>{{ order.nickname }}</QItemLabel>
<QItemLabel>{{ order.agency }}</QItemLabel>
<QItemLabel>{{ order.address.nickname }}</QItemLabel>
<QItemLabel>{{ order.agencyMode.description }}</QItemLabel>
<QItemLabel>{{ currency(order.taxableBase) }}</QItemLabel>
</template>
<template #actions>

18
src/utils/onUserId.js Normal file
View File

@ -0,0 +1,18 @@
import { watch } from 'vue';
import { useUserStore } from 'stores/user';
const userStore = useUserStore();
export const onUserId = (cb) => watch(
() => userStore?.user?.id,
async userId => {
if (!userId) return;

Usando clausulas de guarda podemos quitar un nivel de indexación
if (!userId) return;

Usando clausulas de guarda podemos quitar un nivel de indexación ` if (!userId) return;`
try {
await cb(userId);
} catch (error) {
console.error(error);
}
},
{ immediate: true }
);