|
@@ -49,6 +49,8 @@
|
|
|
let orderDetailModalVisible = false;
|
|
let orderDetailModalVisible = false;
|
|
|
let orderDetailSelected = null;
|
|
let orderDetailSelected = null;
|
|
|
let orderDetailEntries = [];
|
|
let orderDetailEntries = [];
|
|
|
|
|
+ let orderCancelLoading = false;
|
|
|
|
|
+ let orderCancelError = '';
|
|
|
let orderPaymentId = null;
|
|
let orderPaymentId = null;
|
|
|
let orderPaymentCode = '';
|
|
let orderPaymentCode = '';
|
|
|
let orderPaymentExternalId = '';
|
|
let orderPaymentExternalId = '';
|
|
@@ -179,9 +181,32 @@
|
|
|
'currencyId',
|
|
'currencyId',
|
|
|
'Currency_id',
|
|
'Currency_id',
|
|
|
'CurrencyId',
|
|
'CurrencyId',
|
|
|
- 'CURRENCY_ID'
|
|
|
|
|
|
|
+ 'CURRENCY_ID',
|
|
|
|
|
+ 'editable',
|
|
|
|
|
+ 'Editable',
|
|
|
|
|
+ 'EDITABLE'
|
|
|
]);
|
|
]);
|
|
|
|
|
|
|
|
|
|
+ function normalizeBoolean(value) {
|
|
|
|
|
+ if (value === true || value === false) return value;
|
|
|
|
|
+ if (typeof value === 'number') return value === 1;
|
|
|
|
|
+ if (typeof value === 'string') {
|
|
|
|
|
+ const normalized = value.trim().toLowerCase();
|
|
|
|
|
+ if (normalized === 'true') return true;
|
|
|
|
|
+ if (normalized === 'false') return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function resolveOrderEditable(order = {}) {
|
|
|
|
|
+ const raw = order?.raw && typeof order.raw === 'object' ? order.raw : order;
|
|
|
|
|
+ return normalizeBoolean(raw?.editable);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function resolveOrderbookId(order = {}) {
|
|
|
|
|
+ return order?.orderbookId ?? order?.orderbook_id ?? order?.raw?.orderbook_id ?? order?.raw?.orderbookId ?? null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
const orderDetailFieldConfig = [
|
|
const orderDetailFieldConfig = [
|
|
|
{
|
|
{
|
|
|
keys: ['orderbook_flag', 'orderbookFlag'],
|
|
keys: ['orderbook_flag', 'orderbookFlag'],
|
|
@@ -316,10 +341,13 @@
|
|
|
city: resolvedCity,
|
|
city: resolvedCity,
|
|
|
cityName: resolvedCity,
|
|
cityName: resolvedCity,
|
|
|
measureUnitName: resolvedMeasureUnit,
|
|
measureUnitName: resolvedMeasureUnit,
|
|
|
- orderbookId: order?.orderbookId ?? order?.orderbook_id ?? order?.raw?.orderbook_id ?? null,
|
|
|
|
|
|
|
+ orderbookId: resolveOrderbookId(order),
|
|
|
tokenExternalId: order?.tokenExternalId ?? order?.token_external_id ?? order?.raw?.token_external_id ?? '',
|
|
tokenExternalId: order?.tokenExternalId ?? order?.token_external_id ?? order?.raw?.token_external_id ?? '',
|
|
|
|
|
+ editable: resolveOrderEditable(order),
|
|
|
raw: order?.raw ?? order
|
|
raw: order?.raw ?? order
|
|
|
};
|
|
};
|
|
|
|
|
+ orderCancelError = '';
|
|
|
|
|
+ orderCancelLoading = false;
|
|
|
orderDetailEntries = buildOrderDetailEntries(orderDetailSelected);
|
|
orderDetailEntries = buildOrderDetailEntries(orderDetailSelected);
|
|
|
orderDetailModalVisible = true;
|
|
orderDetailModalVisible = true;
|
|
|
}
|
|
}
|
|
@@ -328,6 +356,51 @@
|
|
|
orderDetailModalVisible = false;
|
|
orderDetailModalVisible = false;
|
|
|
orderDetailEntries = [];
|
|
orderDetailEntries = [];
|
|
|
orderDetailSelected = null;
|
|
orderDetailSelected = null;
|
|
|
|
|
+ orderCancelError = '';
|
|
|
|
|
+ orderCancelLoading = false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async function cancelOrderbookOrder() {
|
|
|
|
|
+ if (orderCancelLoading) return;
|
|
|
|
|
+ orderCancelError = '';
|
|
|
|
|
+
|
|
|
|
|
+ const orderbookIdRaw = resolveOrderbookId(orderDetailSelected);
|
|
|
|
|
+ const orderbookId = Number(orderbookIdRaw);
|
|
|
|
|
+ if (!Number.isInteger(orderbookId) || orderbookId <= 0) {
|
|
|
|
|
+ orderCancelError = 'Ordem inválida para cancelamento.';
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const token = get(authToken);
|
|
|
|
|
+ if (!token) {
|
|
|
|
|
+ orderCancelError = 'Sessão expirada. Faça login novamente.';
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ orderCancelLoading = true;
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res = await fetch(`${apiUrl}/orderbook/cancel`, {
|
|
|
|
|
+ method: 'POST',
|
|
|
|
|
+ headers: {
|
|
|
|
|
+ 'content-type': 'application/json',
|
|
|
|
|
+ Authorization: `Bearer ${token}`
|
|
|
|
|
+ },
|
|
|
|
|
+ body: JSON.stringify({ orderbook_id: orderbookId })
|
|
|
|
|
+ });
|
|
|
|
|
+ const body = await parseResponse(res);
|
|
|
|
|
+ const isSuccess = res.ok && body?.status === 'ok' && body?.code === 'S_ORDERBOOK_STATUS_UPDATED';
|
|
|
|
|
+ if (!isSuccess) {
|
|
|
|
|
+ throw new Error(body?.msg ?? body?.message ?? 'Falha ao cancelar ordem.');
|
|
|
|
|
+ }
|
|
|
|
|
+ orderbookSuccessMessage = body?.msg ?? 'Ordem cancelada com sucesso.';
|
|
|
|
|
+ closeOrderDetailModal();
|
|
|
|
|
+ await fetchOrderbook(selectedState, selectedCommodity);
|
|
|
|
|
+ } catch (err) {
|
|
|
|
|
+ console.error('[Trading] Falha ao cancelar ordem do orderbook:', err);
|
|
|
|
|
+ orderCancelError = err?.message ?? 'Não foi possível cancelar a ordem.';
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ orderCancelLoading = false;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function handleOrderDetailPurchase() {
|
|
function handleOrderDetailPurchase() {
|
|
@@ -1364,6 +1437,12 @@ $: displayPendingSells = pendingSells.map((o) => ({
|
|
|
{/if}
|
|
{/if}
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
+ {#if orderCancelError}
|
|
|
|
|
+ <div class="rounded border border-red-200 dark:border-red-700 bg-red-50 dark:bg-red-900/30 text-red-700 dark:text-red-200 px-3 py-2 text-sm">
|
|
|
|
|
+ {orderCancelError}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ {/if}
|
|
|
|
|
+
|
|
|
<div class="flex flex-col gap-2">
|
|
<div class="flex flex-col gap-2">
|
|
|
<button
|
|
<button
|
|
|
class="w-full rounded bg-green-600 hover:bg-green-700 text-white font-semibold py-2 disabled:opacity-60"
|
|
class="w-full rounded bg-green-600 hover:bg-green-700 text-white font-semibold py-2 disabled:opacity-60"
|
|
@@ -1372,13 +1451,16 @@ $: displayPendingSells = pendingSells.map((o) => ({
|
|
|
>
|
|
>
|
|
|
Comprar esta ordem
|
|
Comprar esta ordem
|
|
|
</button>
|
|
</button>
|
|
|
- <button
|
|
|
|
|
- type="button"
|
|
|
|
|
- class="w-full rounded border border-gray-300 dark:border-gray-600 py-2 text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-800"
|
|
|
|
|
- on:click={closeOrderDetailModal}
|
|
|
|
|
- >
|
|
|
|
|
- Cancelar
|
|
|
|
|
- </button>
|
|
|
|
|
|
|
+ {#if orderDetailSelected?.editable}
|
|
|
|
|
+ <button
|
|
|
|
|
+ type="button"
|
|
|
|
|
+ class="w-full rounded border border-gray-300 dark:border-gray-600 py-2 text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-800 disabled:opacity-60"
|
|
|
|
|
+ on:click={cancelOrderbookOrder}
|
|
|
|
|
+ disabled={orderCancelLoading}
|
|
|
|
|
+ >
|
|
|
|
|
+ {orderCancelLoading ? 'Cancelando...' : 'Cancelar'}
|
|
|
|
|
+ </button>
|
|
|
|
|
+ {/if}
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
{:else}
|
|
{:else}
|