fix: selfpayMode state vars + monolith.sh TPV port + closures report
- Add missing selfpayMode/closePin state vars in admin POS page - Add selfpayMode/closeSessionRequiresPin/closeSessionPin to PosTerminal interface - Fix ClosedSession type in reporting/closures to match cash-close endpoint - Add smtpReportEmail to admin StoreSettings interface - monolith.sh: add TPV service (port 3002), reorder ports: API 3000, ADMIN 3001, TPV 3002, FRONTEND 3003, STOREFRONT 3004 - Add apps/pos to install_dependencies in monolith.sh
This commit is contained in:
@@ -19,6 +19,9 @@ interface PosTerminal {
|
|||||||
touchNavigationEnabled?: boolean;
|
touchNavigationEnabled?: boolean;
|
||||||
quickProductVariantIds?: Array<string | null>;
|
quickProductVariantIds?: Array<string | null>;
|
||||||
lineDiscountsEnabled?: boolean;
|
lineDiscountsEnabled?: boolean;
|
||||||
|
selfpayMode?: boolean;
|
||||||
|
closeSessionRequiresPin?: boolean;
|
||||||
|
closeSessionPin?: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
interface CatalogOption {
|
interface CatalogOption {
|
||||||
@@ -94,6 +97,12 @@ export default function PosAdminPage() {
|
|||||||
);
|
);
|
||||||
const [savingTouch, setSavingTouch] = useState(false);
|
const [savingTouch, setSavingTouch] = useState(false);
|
||||||
const [touchMessage, setTouchMessage] = useState('');
|
const [touchMessage, setTouchMessage] = useState('');
|
||||||
|
// F-203: cash close security settings
|
||||||
|
const [selfpayMode, setSelfpayMode] = useState(false);
|
||||||
|
const [closePinRequired, setClosePinRequired] = useState(false);
|
||||||
|
const [closePinValue, setClosePinValue] = useState('');
|
||||||
|
const [savingSecurity, setSavingSecurity] = useState(false);
|
||||||
|
const [securityMessage, setSecurityMessage] = useState('');
|
||||||
const [paymentMethods, setPaymentMethods] = useState<PaymentMethod[]>([]);
|
const [paymentMethods, setPaymentMethods] = useState<PaymentMethod[]>([]);
|
||||||
const [cashiers, setCashiers] = useState<PosCashier[]>([]);
|
const [cashiers, setCashiers] = useState<PosCashier[]>([]);
|
||||||
const [newCashier, setNewCashier] = useState({ email: '', password: '' });
|
const [newCashier, setNewCashier] = useState({ email: '', password: '' });
|
||||||
|
|||||||
@@ -3,6 +3,16 @@
|
|||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { api } from '@/lib/api-client';
|
import { api } from '@/lib/api-client';
|
||||||
|
|
||||||
|
interface SalesSummary {
|
||||||
|
totalCount: number;
|
||||||
|
completedCount: number;
|
||||||
|
completedTotalCents: number;
|
||||||
|
pendingCount: number;
|
||||||
|
refundedCount: number;
|
||||||
|
refundedTotalCents: number;
|
||||||
|
byState: Record<string, { count: number; totalCents: number }>;
|
||||||
|
}
|
||||||
|
|
||||||
interface ClosedSession {
|
interface ClosedSession {
|
||||||
id: string;
|
id: string;
|
||||||
openedAt: string;
|
openedAt: string;
|
||||||
@@ -13,12 +23,9 @@ interface ClosedSession {
|
|||||||
closingCashCents: number | null;
|
closingCashCents: number | null;
|
||||||
actualCashCents: number | null;
|
actualCashCents: number | null;
|
||||||
differenceCents: number | null;
|
differenceCents: number | null;
|
||||||
salesCount: number;
|
sales: SalesSummary;
|
||||||
salesTotalCents: number;
|
|
||||||
salesByState: Record<string, { count: number; totalCents: number }>;
|
|
||||||
paymentsByMethod: Array<{ methodCode: string; methodName: string; totalCents: number; count: number }>;
|
paymentsByMethod: Array<{ methodCode: string; methodName: string; totalCents: number; count: number }>;
|
||||||
itemsSold: number;
|
items: { soldCount: number; uniqueProducts: number };
|
||||||
uniqueProductsSold: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function fmt(cents: number): string {
|
function fmt(cents: number): string {
|
||||||
@@ -240,11 +247,11 @@ export default function ReportingClosuresPage() {
|
|||||||
))}
|
))}
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs text-gray-500">Artículos vendidos</p>
|
<p className="text-xs text-gray-500">Artículos vendidos</p>
|
||||||
<p className="text-lg font-bold text-gray-900">{report.itemsSold}</p>
|
<p className="text-lg font-bold text-gray-900">{report.items.soldCount}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs text-gray-500">Productos únicos</p>
|
<p className="text-xs text-gray-500">Productos únicos</p>
|
||||||
<p className="text-lg font-bold text-gray-900">{report.uniqueProductsSold}</p>
|
<p className="text-lg font-bold text-gray-900">{report.items.uniqueProducts}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -384,6 +384,7 @@ export interface StoreSettings {
|
|||||||
smtpPass: string;
|
smtpPass: string;
|
||||||
smtpPassConfigured?: boolean;
|
smtpPassConfigured?: boolean;
|
||||||
smtpFrom: string;
|
smtpFrom: string;
|
||||||
|
smtpReportEmail: string;
|
||||||
couriers?: string[];
|
couriers?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,13 +11,14 @@ ACTION="${2:-}"
|
|||||||
RUNTIME_ROOT="${MDV_RUNTIME_DIR:-$PROJECT_DIR/.runtime}"
|
RUNTIME_ROOT="${MDV_RUNTIME_DIR:-$PROJECT_DIR/.runtime}"
|
||||||
RUNTIME_DIR="$RUNTIME_ROOT/$MODE"
|
RUNTIME_DIR="$RUNTIME_ROOT/$MODE"
|
||||||
BACKEND_PORT="${BACKEND_PORT:-3000}"
|
BACKEND_PORT="${BACKEND_PORT:-3000}"
|
||||||
|
ADMIN_PORT="${ADMIN_PORT:-3001}"
|
||||||
|
TPV_PORT="${TPV_PORT:-3002}"
|
||||||
FRONTEND_PORT="${FRONTEND_PORT:-3003}"
|
FRONTEND_PORT="${FRONTEND_PORT:-3003}"
|
||||||
ADMIN_PORT="${ADMIN_PORT:-3004}"
|
STOREFRONT_PORT="${STOREFRONT_PORT:-3004}"
|
||||||
STOREFRONT_PORT="${STOREFRONT_PORT:-3005}"
|
|
||||||
START_TIMEOUT="${START_TIMEOUT:-90}"
|
START_TIMEOUT="${START_TIMEOUT:-90}"
|
||||||
WATCH_INTERVAL="${WATCH_INTERVAL:-5}"
|
WATCH_INTERVAL="${WATCH_INTERVAL:-5}"
|
||||||
|
|
||||||
SERVICES=(backend frontend admin storefront)
|
SERVICES=(backend admin tpv frontend storefront)
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
cat <<'EOF'
|
cat <<'EOF'
|
||||||
@@ -75,10 +76,11 @@ API_PUBLIC_URL="${API_PUBLIC_URL:-http://$LAN_ADDRESS:$BACKEND_PORT}"
|
|||||||
|
|
||||||
service_port() {
|
service_port() {
|
||||||
case "$1" in
|
case "$1" in
|
||||||
backend) echo "$BACKEND_PORT" ;;
|
backend) echo "$BACKEND_PORT" ;;
|
||||||
frontend) echo "$FRONTEND_PORT" ;;
|
admin) echo "$ADMIN_PORT" ;;
|
||||||
admin) echo "$ADMIN_PORT" ;;
|
tpv) echo "$TPV_PORT" ;;
|
||||||
storefront) echo "$STOREFRONT_PORT" ;;
|
frontend) echo "$FRONTEND_PORT" ;;
|
||||||
|
storefront) echo "$STOREFRONT_PORT" ;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,7 +187,7 @@ start_infrastructure() {
|
|||||||
install_dependencies() {
|
install_dependencies() {
|
||||||
local install_command=(npm install)
|
local install_command=(npm install)
|
||||||
[[ "$MODE" == "prod" ]] && install_command=(npm ci)
|
[[ "$MODE" == "prod" ]] && install_command=(npm ci)
|
||||||
for dir in "$PROJECT_DIR" "$PROJECT_DIR/apps/admin" "$PROJECT_DIR/frontend" "$PROJECT_DIR/storefront"; do
|
for dir in "$PROJECT_DIR" "$PROJECT_DIR/apps/admin" "$PROJECT_DIR/apps/pos" "$PROJECT_DIR/frontend" "$PROJECT_DIR/storefront"; do
|
||||||
echo "[INFO] ${install_command[*]} — ${dir#$PROJECT_DIR/}"
|
echo "[INFO] ${install_command[*]} — ${dir#$PROJECT_DIR/}"
|
||||||
(cd "$dir" && "${install_command[@]}")
|
(cd "$dir" && "${install_command[@]}")
|
||||||
done
|
done
|
||||||
@@ -257,6 +259,12 @@ spawn_service() {
|
|||||||
prod:admin)
|
prod:admin)
|
||||||
(cd "$PROJECT_DIR/apps/admin" && nohup env NEXT_PUBLIC_API_URL="$API_PUBLIC_URL" node node_modules/next/dist/bin/next start --hostname 0.0.0.0 --port "$port" >"$log" 2>&1 < /dev/null & disown; echo $! >"$pidfile")
|
(cd "$PROJECT_DIR/apps/admin" && nohup env NEXT_PUBLIC_API_URL="$API_PUBLIC_URL" node node_modules/next/dist/bin/next start --hostname 0.0.0.0 --port "$port" >"$log" 2>&1 < /dev/null & disown; echo $! >"$pidfile")
|
||||||
;;
|
;;
|
||||||
|
dev:tpv)
|
||||||
|
(cd "$PROJECT_DIR/apps/pos" && nohup env NEXT_PUBLIC_API_URL="$API_PUBLIC_URL" node node_modules/next/dist/bin/next dev --hostname 0.0.0.0 --port "$port" >"$log" 2>&1 < /dev/null & disown; echo $! >"$pidfile")
|
||||||
|
;;
|
||||||
|
prod:tpv)
|
||||||
|
(cd "$PROJECT_DIR/apps/pos" && nohup env NEXT_PUBLIC_API_URL="$API_PUBLIC_URL" node node_modules/next/dist/bin/next start --hostname 0.0.0.0 --port "$port" >"$log" 2>&1 < /dev/null & disown; echo $! >"$pidfile")
|
||||||
|
;;
|
||||||
dev:frontend)
|
dev:frontend)
|
||||||
(cd "$PROJECT_DIR/frontend" && nohup env NEXT_PUBLIC_API_URL="$API_PUBLIC_URL" node node_modules/next/dist/bin/next dev --hostname 0.0.0.0 --port "$port" >"$log" 2>&1 < /dev/null & disown; echo $! >"$pidfile")
|
(cd "$PROJECT_DIR/frontend" && nohup env NEXT_PUBLIC_API_URL="$API_PUBLIC_URL" node node_modules/next/dist/bin/next dev --hostname 0.0.0.0 --port "$port" >"$log" 2>&1 < /dev/null & disown; echo $! >"$pidfile")
|
||||||
;;
|
;;
|
||||||
@@ -384,8 +392,10 @@ print_urls() {
|
|||||||
Mode: $MODE
|
Mode: $MODE
|
||||||
LAN IP: $LAN_ADDRESS
|
LAN IP: $LAN_ADDRESS
|
||||||
|
|
||||||
Customer frontend: http://$LAN_ADDRESS:$FRONTEND_PORT/
|
Backend (API): http://$LAN_ADDRESS:$BACKEND_PORT/health
|
||||||
Admin backoffice: http://$LAN_ADDRESS:$ADMIN_PORT/
|
Admin backoffice: http://$LAN_ADDRESS:$ADMIN_PORT/
|
||||||
|
POS TPV: http://$LAN_ADDRESS:$TPV_PORT/
|
||||||
|
Customer frontend: http://$LAN_ADDRESS:$FRONTEND_PORT/
|
||||||
SEO storefront: http://$LAN_ADDRESS:$STOREFRONT_PORT/
|
SEO storefront: http://$LAN_ADDRESS:$STOREFRONT_PORT/
|
||||||
Backend health: http://$LAN_ADDRESS:$BACKEND_PORT/health
|
Backend health: http://$LAN_ADDRESS:$BACKEND_PORT/health
|
||||||
Swagger/OpenAPI: http://$LAN_ADDRESS:$BACKEND_PORT/docs
|
Swagger/OpenAPI: http://$LAN_ADDRESS:$BACKEND_PORT/docs
|
||||||
|
|||||||
Reference in New Issue
Block a user