diff --git a/app/api/job/test-medipost-responses/route.ts b/app/api/job/test-medipost-responses/route.ts index 4ca8be0..3b32794 100644 --- a/app/api/job/test-medipost-responses/route.ts +++ b/app/api/job/test-medipost-responses/route.ts @@ -41,8 +41,6 @@ export async function POST(request: NextRequest) { orderCreatedAt: new Date(medreportOrder.created_at), }); - console.info("SEND XML", messageXml); - try { await sendPrivateMessageTestResponse({ messageXml }); } catch (error) { diff --git a/app/api/order/medipost-test-response/route.ts b/app/api/order/medipost-test-response/route.ts index 40cf4b2..a54e1fe 100644 --- a/app/api/order/medipost-test-response/route.ts +++ b/app/api/order/medipost-test-response/route.ts @@ -3,7 +3,7 @@ import { getOrder } from "~/lib/services/order.service"; import { composeOrderTestResponseXML, sendPrivateMessageTestResponse } from "~/lib/services/medipostTest.service"; import { retrieveOrder } from "@lib/data"; import { getAccountAdmin } from "~/lib/services/account.service"; -import { getOrderedAnalysisElementsIds } from "~/lib/services/medipost.service"; +import { createMedipostActionLog, getOrderedAnalysisElementsIds } from "~/lib/services/medipost.service"; export async function POST(request: Request) { // const isDev = process.env.NODE_ENV === 'development'; @@ -35,6 +35,11 @@ export async function POST(request: Request) { }); try { + await createMedipostActionLog({ + action: 'send_fake_analysis_results_to_medipost', + xml: messageXml, + medusaOrderId, + }); await sendPrivateMessageTestResponse({ messageXml }); } catch (error) { console.error("Error sending private message test response: ", error); diff --git a/app/home/(user)/_components/home-menu-navigation.tsx b/app/home/(user)/_components/home-menu-navigation.tsx index fb91de9..473a681 100644 --- a/app/home/(user)/_components/home-menu-navigation.tsx +++ b/app/home/(user)/_components/home-menu-navigation.tsx @@ -31,8 +31,8 @@ export async function HomeMenuNavigation(props: { }) : 0; - const cartItemsCount = props.cart?.items?.length ?? 0; - const hasCartItems = cartItemsCount > 0; + const cartQuantityTotal = props.cart?.items?.reduce((acc, item) => acc + item.quantity, 0) ?? 0; + const hasCartItems = cartQuantityTotal > 0; return (
@@ -64,7 +64,7 @@ export async function HomeMenuNavigation(props: { diff --git a/app/home/(user)/_components/home-mobile-navigation.tsx b/app/home/(user)/_components/home-mobile-navigation.tsx index a363a4c..7ead53a 100644 --- a/app/home/(user)/_components/home-mobile-navigation.tsx +++ b/app/home/(user)/_components/home-mobile-navigation.tsx @@ -51,8 +51,8 @@ export function HomeMobileNavigation(props: { } }); - const cartItemsCount = props.cart?.items?.length ?? 0; - const hasCartItems = cartItemsCount > 0; + const cartQuantityTotal = props.cart?.items?.reduce((acc, item) => acc + item.quantity, 0) ?? 0; + const hasCartItems = cartQuantityTotal > 0; return ( @@ -83,7 +83,7 @@ export function HomeMobileNavigation(props: { path="/home/cart" label="common:shoppingCartCount" Icon={} - labelOptions={{ count: cartItemsCount }} + labelOptions={{ count: cartQuantityTotal }} /> diff --git a/app/home/(user)/_components/order-analyses-cards.tsx b/app/home/(user)/_components/order-analyses-cards.tsx index b6a2d75..23b88b5 100644 --- a/app/home/(user)/_components/order-analyses-cards.tsx +++ b/app/home/(user)/_components/order-analyses-cards.tsx @@ -12,9 +12,9 @@ import { import { StoreProduct } from '@medusajs/types'; import { useState } from 'react'; import { handleAddToCart } from '~/lib/services/medusaCart.service'; -import { useRouter } from 'next/navigation'; import { InfoTooltip } from '@kit/shared/components/ui/info-tooltip'; import { Trans } from '@kit/ui/trans'; +import { toast } from '@kit/ui/sonner'; export type OrderAnalysisCard = Pick< StoreProduct, 'title' | 'description' | 'subtitle' @@ -30,8 +30,6 @@ export default function OrderAnalysesCards({ analyses: OrderAnalysisCard[]; countryCode: string; }) { - const router = useRouter(); - const [isAddingToCart, setIsAddingToCart] = useState(false); const handleSelect = async (variantId: string) => { if (isAddingToCart) { @@ -44,9 +42,10 @@ export default function OrderAnalysesCards({ selectedVariant: { id: variantId }, countryCode, }); + toast.success(); setIsAddingToCart(false); - router.push('/home/cart'); } catch (e) { + toast.error(); setIsAddingToCart(false); console.error(e); } diff --git a/app/home/(user)/_components/orders/actions.ts b/app/home/(user)/_components/orders/actions.ts new file mode 100644 index 0000000..d201507 --- /dev/null +++ b/app/home/(user)/_components/orders/actions.ts @@ -0,0 +1,18 @@ +'use server'; + +import { createPageViewLog, PageViewAction } from "~/lib/services/audit/pageView.service"; +import { loadCurrentUserAccount } from "../../_lib/server/load-user-account"; + +export async function logAnalysisResultsNavigateAction(analysisOrderId: string) { + const account = await loadCurrentUserAccount(); + if (!account) { + throw new Error('Account not found'); + } + await createPageViewLog({ + accountId: account.id, + action: PageViewAction.VIEW_ANALYSIS_RESULTS_FROM_ORDER, + extraData: { + analysisOrderId, + }, + }); +} diff --git a/app/home/(user)/_components/orders/order-items-table.tsx b/app/home/(user)/_components/orders/order-items-table.tsx index 48d502a..096ad06 100644 --- a/app/home/(user)/_components/orders/order-items-table.tsx +++ b/app/home/(user)/_components/orders/order-items-table.tsx @@ -1,3 +1,5 @@ +'use client'; + import { Trans } from '@kit/ui/trans'; import { Table, @@ -10,18 +12,26 @@ import { import { StoreOrderLineItem } from "@medusajs/types"; import { AnalysisOrder } from '~/lib/services/order.service'; import { formatDate } from 'date-fns'; -import Link from 'next/link'; import { Eye } from 'lucide-react'; +import { useRouter } from 'next/navigation'; +import { logAnalysisResultsNavigateAction } from './actions'; export default function OrderItemsTable({ items, title, analysisOrder }: { items: StoreOrderLineItem[]; title: string; analysisOrder: AnalysisOrder; }) { + const router = useRouter(); + if (!items || items.length === 0) { return null; } + const openAnalysisResults = async () => { + await logAnalysisResultsNavigateAction(analysisOrder.medusa_order_id); + router.push(`/home/analysis-results`); + } + return ( @@ -60,13 +70,12 @@ export default function OrderItemsTable({ items, title, analysisOrder }: { - - - + diff --git a/lib/services/audit/pageView.service.ts b/lib/services/audit/pageView.service.ts index f4e70f6..efac5db 100644 --- a/lib/services/audit/pageView.service.ts +++ b/lib/services/audit/pageView.service.ts @@ -2,6 +2,7 @@ import { getSupabaseServerClient } from '@kit/supabase/server-client'; export enum PageViewAction { VIEW_ANALYSIS_RESULTS = 'VIEW_ANALYSIS_RESULTS', + VIEW_ANALYSIS_RESULTS_FROM_ORDER = 'VIEW_ANALYSIS_RESULTS_FROM_ORDER', REGISTRATION_SUCCESS = 'REGISTRATION_SUCCESS', VIEW_ORDER_ANALYSIS = 'VIEW_ORDER_ANALYSIS', VIEW_TEAM_ACCOUNT_DASHBOARD = 'VIEW_TEAM_ACCOUNT_DASHBOARD', @@ -10,9 +11,11 @@ export enum PageViewAction { export const createPageViewLog = async ({ accountId, action, + extraData, }: { accountId: string; action: PageViewAction; + extraData?: Record; }) => { try { const supabase = getSupabaseServerClient(); @@ -34,6 +37,7 @@ export const createPageViewLog = async ({ account_id: accountId, action, changed_by: user.id, + extra_data: extraData, }) .throwOnError(); } catch (error) { diff --git a/lib/services/medipost.service.ts b/lib/services/medipost.service.ts index 542f275..a32b624 100644 --- a/lib/services/medipost.service.ts +++ b/lib/services/medipost.service.ts @@ -180,7 +180,10 @@ export async function getPrivateMessage(messageId: string) { await validateMedipostResponse(data, { canHaveEmptyCode: true }); - return parseXML(data) as MedipostOrderResponse; + return { + message: parseXML(data) as MedipostOrderResponse, + xml: data as string, + }; } export async function deletePrivateMessage(messageId: string) { @@ -211,7 +214,9 @@ export async function readPrivateMessageResponse({ try { const privateMessage = await getLatestPrivateMessageListItem({ excludedMessageIds }); - if (!privateMessage) { + messageId = privateMessage?.messageId ?? null; + + if (!privateMessage || !messageId) { return { messageId: null, hasAnalysisResponse: false, @@ -221,40 +226,28 @@ export async function readPrivateMessageResponse({ }; } - messageId = privateMessage.messageId; - if (!messageId) { - return { - messageId: null, - hasAnalysisResponse: false, - hasPartialAnalysisResponse: false, - hasFullAnalysisResponse: false, - medusaOrderId: undefined, - }; - } - - const privateMessageContent = await getPrivateMessage( + const { message: privateMessageContent, xml: privateMessageXml } = await getPrivateMessage( privateMessage.messageId, ); + const messageResponse = privateMessageContent?.Saadetis?.Vastus; medusaOrderId = privateMessageContent?.Saadetis?.Tellimus?.ValisTellimuseId || messageResponse?.ValisTellimuseId; - if (!medusaOrderId || !medusaOrderId.toString().startsWith('order_')) { - return { - messageId, - hasAnalysisResponse: false, - hasPartialAnalysisResponse: false, - hasFullAnalysisResponse: false, - medusaOrderId: undefined, - }; - } + const hasInvalidOrderId = !medusaOrderId || !medusaOrderId.toString().startsWith('order_'); - if (!messageResponse) { + if (hasInvalidOrderId || !messageResponse) { + await createMedipostActionLog({ + action: 'sync_analysis_results_from_medipost', + xml: privateMessageXml, + hasAnalysisResults: false, + medusaOrderId: hasInvalidOrderId ? undefined : medusaOrderId, + }); return { messageId, hasAnalysisResponse: false, hasPartialAnalysisResponse: false, hasFullAnalysisResponse: false, - medusaOrderId, + medusaOrderId: hasInvalidOrderId ? undefined : medusaOrderId, }; } @@ -745,12 +738,36 @@ export async function sendOrderToMedipost({ await sendPrivateMessage(orderXml); } catch (e) { const isMedipostError = e instanceof MedipostValidationError; - await logMedipostDispatch({ - medusaOrderId, - isSuccess: false, - isMedipostError, - errorMessage: isMedipostError ? e.response : undefined, - }); + if (isMedipostError) { + await logMedipostDispatch({ + medusaOrderId, + isSuccess: false, + isMedipostError, + errorMessage: e.response, + }); + await createMedipostActionLog({ + action: 'send_order_to_medipost', + xml: orderXml, + hasAnalysisResults: false, + medusaOrderId, + responseXml: e.response, + hasError: true, + }); + } else { + await logMedipostDispatch({ + medusaOrderId, + isSuccess: false, + isMedipostError, + }); + await createMedipostActionLog({ + action: 'send_order_to_medipost', + xml: orderXml, + hasAnalysisResults: false, + medusaOrderId, + hasError: true, + }); + } + throw e; } await logMedipostDispatch({ @@ -758,6 +775,12 @@ export async function sendOrderToMedipost({ isSuccess: true, isMedipostError: false, }); + await createMedipostActionLog({ + action: 'send_order_to_medipost', + xml: orderXml, + hasAnalysisResults: false, + medusaOrderId, + }); await updateOrderStatus({ medusaOrderId, orderStatus: 'PROCESSING' }); } @@ -825,3 +848,37 @@ export async function getOrderedAnalysisElementsIds({ return [...analysisPackageElements, ...orderedAnalysisElements]; } + +export async function createMedipostActionLog({ + action, + xml, + hasAnalysisResults = false, + medusaOrderId, + responseXml, + hasError = false, +}: { + action: + | 'send_order_to_medipost' + | 'sync_analysis_results_from_medipost' + | 'send_fake_analysis_results_to_medipost' + | 'send_analysis_results_to_medipost'; + xml: string; + hasAnalysisResults?: boolean; + medusaOrderId?: string | null; + responseXml?: string | null; + hasError?: boolean; +}) { + await getSupabaseServerAdminClient() + .schema('medreport') + .from('medipost_actions') + .insert({ + action, + xml, + has_analysis_results: hasAnalysisResults, + medusa_order_id: medusaOrderId, + response_xml: responseXml, + has_error: hasError, + }) + .select('id') + .throwOnError(); +} diff --git a/lib/services/order.service.ts b/lib/services/order.service.ts index 8afb4c4..e7ca441 100644 --- a/lib/services/order.service.ts +++ b/lib/services/order.service.ts @@ -134,8 +134,10 @@ export async function getAnalysisOrders({ export async function getAnalysisOrdersAdmin({ orderStatus, + medusaOrderId, }: { orderStatus?: Tables<{ schema: 'medreport' }, 'analysis_orders'>['status']; + medusaOrderId?: string | null; } = {}) { const query = getSupabaseServerAdminClient() .schema('medreport') @@ -144,6 +146,9 @@ export async function getAnalysisOrdersAdmin({ if (orderStatus) { query.eq('status', orderStatus); } + if (medusaOrderId) { + query.eq('medusa_order_id', medusaOrderId); + } const orders = await query.order('created_at', { ascending: false }).throwOnError(); return orders.data; } diff --git a/packages/shared/src/components/select-analysis-package.tsx b/packages/shared/src/components/select-analysis-package.tsx index 1709138..9f87183 100644 --- a/packages/shared/src/components/select-analysis-package.tsx +++ b/packages/shared/src/components/select-analysis-package.tsx @@ -9,6 +9,7 @@ import { StoreProduct } from '@medusajs/types'; import { Button } from '@medusajs/ui'; import { useTranslation } from 'react-i18next'; import { handleAddToCart } from '../../../../lib/services/medusaCart.service'; +import { toast } from '@kit/ui/sonner'; import { Card, @@ -49,12 +50,19 @@ export default function SelectAnalysisPackage({ const handleSelect = async () => { setIsAddingToCart(true); - await handleAddToCart({ - selectedVariant: { id: variantId }, - countryCode, - }); - setIsAddingToCart(false); - router.push('/home/cart'); + try { + await handleAddToCart({ + selectedVariant: { id: variantId }, + countryCode, + }); + setIsAddingToCart(false); + toast.success(); + router.push('/home/cart'); + } catch (e) { + toast.error(); + setIsAddingToCart(false); + console.error(e); + } }; return ( diff --git a/packages/supabase/src/database.types.ts b/packages/supabase/src/database.types.ts index 5040c87..33eee12 100644 --- a/packages/supabase/src/database.types.ts +++ b/packages/supabase/src/database.types.ts @@ -199,6 +199,7 @@ export type Database = { changed_by: string created_at: string id: number + extra_data?: Json | null } Insert: { account_id: string @@ -206,6 +207,7 @@ export type Database = { changed_by: string created_at?: string id?: number + extra_data?: Json | null } Update: { account_id?: string @@ -213,6 +215,7 @@ export type Database = { changed_by?: string created_at?: string id?: number + extra_data?: Json | null } Relationships: [] } @@ -1254,6 +1257,34 @@ export type Database = { }, ] } + medipost_actions: { + Row: { + id: string + action: string + xml: string + has_analysis_results: boolean + created_at: string + medusa_order_id: string + response_xml: string + has_error: boolean + } + Insert: { + action: string + xml: string + has_analysis_results: boolean + medusa_order_id: string + response_xml: string + has_error: boolean + } + Update: { + action?: string + xml?: string + has_analysis_results?: boolean + medusa_order_id?: string + response_xml?: string + has_error?: boolean + } + } medreport_product_groups: { Row: { created_at: string @@ -1919,6 +1950,15 @@ export type Database = { account_id: string }[] } + get_latest_medipost_dispatch_state_for_order: { + Args: { + medusa_order_id: string + } + Returns: { + has_success: boolean + action_date: string + } + } get_medipost_dispatch_tries: { Args: { p_medusa_order_id: string } Returns: number @@ -2135,6 +2175,21 @@ export type Database = { } Returns: Json } + sync_analysis_results: { + } + send_medipost_test_response_for_order: { + Args: { + medusa_order_id: string + } + } + order_has_medipost_dispatch_error: { + Args: { + medusa_order_id: string + } + Returns: { + success: boolean + } + } } Enums: { analysis_feedback_status: "STARTED" | "DRAFT" | "COMPLETED" diff --git a/public/locales/en/order-analysis-package.json b/public/locales/en/order-analysis-package.json index 9502bf1..7f93260 100644 --- a/public/locales/en/order-analysis-package.json +++ b/public/locales/en/order-analysis-package.json @@ -1,7 +1,9 @@ { - "title": "Select analysis package", - "noPackagesAvailable": "No packages available", - "selectThisPackage": "Select this package", - "selectPackage": "Select package", - "comparePackages": "Compare packages" + "title": "Select analysis package", + "noPackagesAvailable": "No packages available", + "selectThisPackage": "Select this package", + "selectPackage": "Select package", + "comparePackages": "Compare packages", + "analysisPackageAddedToCart": "Analysis package added to cart", + "analysisPackageAddToCartError": "Adding analysis package to cart failed" } \ No newline at end of file diff --git a/public/locales/en/order-analysis.json b/public/locales/en/order-analysis.json index 6ab9af8..2031316 100644 --- a/public/locales/en/order-analysis.json +++ b/public/locales/en/order-analysis.json @@ -1,5 +1,7 @@ { "title": "Select analysis", - "description": "Select the analysis that suits your needs", - "analysisNotAvailable": "Analysis is not available currently" + "description": "All analysis results will appear within 1-3 days after the blood test.", + "analysisNotAvailable": "Analysis is not available currently", + "analysisAddedToCart": "Analysis added to cart", + "analysisAddToCartError": "Adding analysis to cart failed" } \ No newline at end of file diff --git a/public/locales/et/order-analysis-package.json b/public/locales/et/order-analysis-package.json index 2c44087..fb236a3 100644 --- a/public/locales/et/order-analysis-package.json +++ b/public/locales/et/order-analysis-package.json @@ -1,7 +1,9 @@ { - "title": "Vali analüüsi pakett", - "noPackagesAvailable": "Teenuste loetelu ei leitud, proovi hiljem uuesti", - "selectThisPackage": "Vali see pakett", - "selectPackage": "Vali pakett", - "comparePackages": "Võrdle pakette" + "title": "Vali analüüsi pakett", + "noPackagesAvailable": "Teenuste loetelu ei leitud, proovi hiljem uuesti", + "selectThisPackage": "Vali see pakett", + "selectPackage": "Vali pakett", + "comparePackages": "Võrdle pakette", + "analysisPackageAddedToCart": "Analüüsi pakett lisatud ostukorvi", + "analysisPackageAddToCartError": "Analüüsi paketi lisamine ostukorvi ebaõnnestus" } \ No newline at end of file diff --git a/public/locales/et/order-analysis.json b/public/locales/et/order-analysis.json index 42f790e..9c7b750 100644 --- a/public/locales/et/order-analysis.json +++ b/public/locales/et/order-analysis.json @@ -1,5 +1,7 @@ { "title": "Vali analüüs", - "description": "Vali enda vajadustele sobiv analüüs", - "analysisNotAvailable": "Analüüsi tellimine ei ole hetkel saadaval" + "description": "Kõikide analüüside tulemused ilmuvad 1–3 tööpäeva jooksul peale vere andmist.", + "analysisNotAvailable": "Analüüsi tellimine ei ole hetkel saadaval", + "analysisAddedToCart": "Analüüs lisatud ostukorvi", + "analysisAddToCartError": "Analüüsi lisamine ostukorvi ebaõnnestus" } \ No newline at end of file diff --git a/supabase/migrations-env-specific/20250824112611_enable_cron_net.sql b/supabase/migrations-env-specific/20250824112611_enable_cron_net.sql new file mode 100644 index 0000000..e757d24 --- /dev/null +++ b/supabase/migrations-env-specific/20250824112611_enable_cron_net.sql @@ -0,0 +1,3 @@ +-- Enable required extensions for cron jobs and HTTP requests +create extension if not exists pg_cron; +create extension if not exists pg_net; diff --git a/supabase/migrations/20250825120858_medipost_retry_dispatch.sql b/supabase/migrations-env-specific/20250825120858_medipost_retry_dispatch.sql similarity index 96% rename from supabase/migrations/20250825120858_medipost_retry_dispatch.sql rename to supabase/migrations-env-specific/20250825120858_medipost_retry_dispatch.sql index 73e6e27..c6e13e8 100644 --- a/supabase/migrations/20250825120858_medipost_retry_dispatch.sql +++ b/supabase/migrations-env-specific/20250825120858_medipost_retry_dispatch.sql @@ -1,5 +1,3 @@ -create extension if not exists pg_net; - create or replace function medreport.medipost_retry_dispatch( order_id text ) diff --git a/supabase/migrations-env-specific/20250827090151_bo_run_results_sync.sql b/supabase/migrations-env-specific/20250827090151_bo_run_results_sync.sql new file mode 100644 index 0000000..3bddde6 --- /dev/null +++ b/supabase/migrations-env-specific/20250827090151_bo_run_results_sync.sql @@ -0,0 +1,16 @@ +CREATE OR REPLACE FUNCTION medreport.sync_analysis_results() +RETURNS void +LANGUAGE plpgsql +AS $$ +BEGIN + select net.http_post( + url := 'https://test.medreport.ee/api/job/sync-analysis-results', + headers := jsonb_build_object( + 'Content-Type', 'application/json', + 'x-jobs-api-key', 'fd26ec26-70ed-11f0-9e95-431ac3b15a84' + ) + ) as request_id; +END; +$$; + +grant execute on function medreport.sync_analysis_results() to service_role; diff --git a/supabase/migrations-env-specific/20250827090152_bo_run_dev_fake_results_sync.sql b/supabase/migrations-env-specific/20250827090152_bo_run_dev_fake_results_sync.sql new file mode 100644 index 0000000..4ef9274 --- /dev/null +++ b/supabase/migrations-env-specific/20250827090152_bo_run_dev_fake_results_sync.sql @@ -0,0 +1,19 @@ +CREATE OR REPLACE FUNCTION medreport.send_medipost_test_response_for_order(medusa_order_id text) +RETURNS void +LANGUAGE plpgsql +AS $$ +BEGIN + select net.http_post( + url := 'https://test.medreport.ee/api/order/medipost-test-response', + headers := jsonb_build_object( + 'Content-Type', 'application/json', + 'x-jobs-api-key', 'fd26ec26-70ed-11f0-9e95-431ac3b15a84' + ), + body := jsonb_build_object( + 'medusaOrderId', medusa_order_id + ) + ) as request_id; +END; +$$; + +grant execute on function medreport.send_medipost_test_response_for_order(text) to service_role; diff --git a/schedule-setup/setup_send_analysis_test_results_cron.sql b/supabase/migrations-env-specific/20250828142742_dev__send_analysis_results_cron.sql similarity index 57% rename from schedule-setup/setup_send_analysis_test_results_cron.sql rename to supabase/migrations-env-specific/20250828142742_dev__send_analysis_results_cron.sql index 2562939..e30f016 100644 --- a/schedule-setup/setup_send_analysis_test_results_cron.sql +++ b/supabase/migrations-env-specific/20250828142742_dev__send_analysis_results_cron.sql @@ -1,12 +1,8 @@ --- Enable required extensions for cron jobs and HTTP requests -create extension if not exists pg_cron; -create extension if not exists pg_net; - -- Schedule the test-medipost-responses job to run every 15 minutes select cron.schedule( - 'send-test-medipost-responses-every-15-minutes', -- Unique job name - '*/15 * * * *', -- Cron schedule: every 15 minutes + 'send-test-medipost-responses-every-15-minutes', + '*/15 * * * *', $$ select net.http_post( diff --git a/schedule-setup/setup_sync_analysis_results_cron.sql b/supabase/migrations-env-specific/20250828142742_setup_sync_analysis_results_cron.sql similarity index 76% rename from schedule-setup/setup_sync_analysis_results_cron.sql rename to supabase/migrations-env-specific/20250828142742_setup_sync_analysis_results_cron.sql index 832f982..ed50da0 100644 --- a/schedule-setup/setup_sync_analysis_results_cron.sql +++ b/supabase/migrations-env-specific/20250828142742_setup_sync_analysis_results_cron.sql @@ -1,7 +1,3 @@ --- Enable required extensions for cron jobs and HTTP requests -create extension if not exists pg_cron; -create extension if not exists pg_net; - -- Schedule the sync-analysis-results job to run every 15 minutes select cron.schedule( diff --git a/supabase/migrations-env-specific/README.md b/supabase/migrations-env-specific/README.md new file mode 100644 index 0000000..6d6e833 --- /dev/null +++ b/supabase/migrations-env-specific/README.md @@ -0,0 +1,4 @@ +Migrations that require env specific parameters. + +- JOBS_API_TOKEN +- app deploy public or internal URL diff --git a/supabase/migrations/20250828105844_medipost_actions.sql b/supabase/migrations/20250828105844_medipost_actions.sql new file mode 100644 index 0000000..3eea037 --- /dev/null +++ b/supabase/migrations/20250828105844_medipost_actions.sql @@ -0,0 +1,16 @@ +CREATE TABLE medreport.medipost_actions ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + action VARCHAR(255) NOT NULL, + xml VARCHAR(131072), + has_analysis_results BOOLEAN NOT NULL DEFAULT FALSE, + medusa_order_id VARCHAR(255), + created_at TIMESTAMP WITH TIME ZONE DEFAULT now() +); + +ALTER TABLE medreport.medipost_actions ENABLE ROW LEVEL SECURITY; + +CREATE POLICY "service_role_select" ON medreport.medipost_actions FOR SELECT TO service_role USING (true); +CREATE POLICY "service_role_insert" ON medreport.medipost_actions FOR INSERT TO service_role WITH CHECK (true); +CREATE POLICY "service_role_update" ON medreport.medipost_actions FOR UPDATE TO service_role USING (true); +CREATE POLICY "service_role_delete" ON medreport.medipost_actions FOR DELETE TO service_role USING (true); +grant select, insert, update, delete on table medreport.medipost_actions to service_role; diff --git a/supabase/migrations/20250828121900_medipost_actions_extra_fields.sql b/supabase/migrations/20250828121900_medipost_actions_extra_fields.sql new file mode 100644 index 0000000..6c1f9df --- /dev/null +++ b/supabase/migrations/20250828121900_medipost_actions_extra_fields.sql @@ -0,0 +1,2 @@ +ALTER TABLE medreport.medipost_actions ADD COLUMN response_xml VARCHAR(131072); +ALTER TABLE medreport.medipost_actions ADD COLUMN has_error BOOLEAN NOT NULL DEFAULT FALSE; diff --git a/supabase/migrations/20250828123119_page_views_extra_data.sql b/supabase/migrations/20250828123119_page_views_extra_data.sql new file mode 100644 index 0000000..69f1e3d --- /dev/null +++ b/supabase/migrations/20250828123119_page_views_extra_data.sql @@ -0,0 +1 @@ +ALTER TABLE audit.page_views ADD COLUMN extra_data JSONB; diff --git a/supabase/migrations/20250828133240_show_medipost_dispatch_error_for_order_in_medusa.sql b/supabase/migrations/20250828133240_show_medipost_dispatch_error_for_order_in_medusa.sql new file mode 100644 index 0000000..d72dc89 --- /dev/null +++ b/supabase/migrations/20250828133240_show_medipost_dispatch_error_for_order_in_medusa.sql @@ -0,0 +1,11 @@ +CREATE OR REPLACE FUNCTION medreport.order_has_medipost_dispatch_error(medusa_order_id text) +RETURNS boolean AS $$ +SELECT EXISTS ( + SELECT 1 FROM medreport.medipost_actions + WHERE medusa_order_id = $1 + AND action = 'send_order_to_medipost' + AND has_error = true +); +$$ LANGUAGE sql STABLE; + +grant execute on function medreport.order_has_medipost_dispatch_error(text) to service_role; diff --git a/supabase/migrations/20250828142742_show_medipost_dispatch_success_for_order_in_medusa.sql b/supabase/migrations/20250828142742_show_medipost_dispatch_success_for_order_in_medusa.sql new file mode 100644 index 0000000..2838327 --- /dev/null +++ b/supabase/migrations/20250828142742_show_medipost_dispatch_success_for_order_in_medusa.sql @@ -0,0 +1,16 @@ +CREATE OR REPLACE FUNCTION medreport.get_latest_medipost_dispatch_state_for_order(medusa_order_id text) +RETURNS TABLE(has_success boolean, action_date timestamp with time zone) AS $$ +SELECT + CASE + WHEN ma.has_error = false THEN true + ELSE false + END as has_success, + ma.created_at as action_date +FROM medreport.medipost_actions ma +WHERE ma.medusa_order_id = $1 +AND ma.action = 'send_order_to_medipost' +ORDER BY ma.created_at DESC +LIMIT 1; +$$ LANGUAGE sql STABLE; + +grant execute on function medreport.get_latest_medipost_dispatch_state_for_order(text) to service_role;