Add PO auto-sync from external purchase-orders table
POs now auto-sync from the external DynamoDB purchase-orders table on every GET /pos request, replacing manual import. Adds cursor-based pagination support and SAM template for local development. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
5efa6fc961
commit
3854750597
6 changed files with 376 additions and 57 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -1,5 +1,8 @@
|
||||||
node_modules/
|
node_modules/
|
||||||
cdk.out/
|
cdk.out/
|
||||||
|
.aws-sam/
|
||||||
.env
|
.env
|
||||||
|
env.json
|
||||||
|
env.local.json
|
||||||
*.js.map
|
*.js.map
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,7 @@ class LedgerFlowStack extends cdk.Stack {
|
||||||
EDI_TX_TABLE: ediTxTable.tableName,
|
EDI_TX_TABLE: ediTxTable.tableName,
|
||||||
SESSIONS_TABLE: sessionsTable.tableName,
|
SESSIONS_TABLE: sessionsTable.tableName,
|
||||||
SETTINGS_TABLE: settingsTable.tableName,
|
SETTINGS_TABLE: settingsTable.tableName,
|
||||||
|
PURCHASE_ORDERS_TABLE: "purchase-orders",
|
||||||
EDI_INPUT_BUCKET: ediInputBucket.bucketName,
|
EDI_INPUT_BUCKET: ediInputBucket.bucketName,
|
||||||
EDI_OUTPUT_BUCKET: ediOutputBucket.bucketName,
|
EDI_OUTPUT_BUCKET: ediOutputBucket.bucketName,
|
||||||
// Set these via SSM Parameter Store or Secrets Manager in production:
|
// Set these via SSM Parameter Store or Secrets Manager in production:
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,18 @@
|
||||||
// lambdas/pos/index.js
|
// lambdas/pos/index.js
|
||||||
// Purchase Orders API
|
// Purchase Orders API
|
||||||
// GET /pos — list all POs (paginated, filterable)
|
// GET /pos — list all POs (auto-syncs from purchase-orders table)
|
||||||
// POST /pos — create a single PO manually
|
// POST /pos — create a single PO manually
|
||||||
// GET /pos/:id — get one PO
|
// GET /pos/:id — get one PO
|
||||||
// PUT /pos/:id — full update
|
// PUT /pos/:id — full update
|
||||||
// PATCH /pos/:id — partial update (e.g. status change)
|
// PATCH /pos/:id — partial update (e.g. status change)
|
||||||
// DELETE /pos/:id — delete
|
// DELETE /pos/:id — delete
|
||||||
// POST /pos/import — bulk import (from DynamoDB scan proxy or pasted JSON)
|
// POST /pos/import — bulk import (from pasted JSON)
|
||||||
// GET /pos/dynamo-scan — live scan of the customer's own DynamoDB PO table
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
ScanCommand, GetCommand, PutCommand, UpdateCommand, DeleteCommand,
|
ScanCommand, GetCommand, PutCommand, UpdateCommand, DeleteCommand,
|
||||||
} = require("@aws-sdk/lib-dynamodb");
|
} = require("@aws-sdk/lib-dynamodb");
|
||||||
const {
|
const {
|
||||||
ok, created, noContent, badRequest, notFound, conflict, serverError,
|
ok, created, noContent, badRequest, notFound, conflict,
|
||||||
getDocClient, TABLES, genId, parseBody, require_fields, handler,
|
getDocClient, TABLES, genId, parseBody, require_fields, handler,
|
||||||
parsePagination, paginatedResponse, decodeCursor,
|
parsePagination, paginatedResponse, decodeCursor,
|
||||||
} = require("@ledgerflow/shared");
|
} = require("@ledgerflow/shared");
|
||||||
|
|
@ -32,8 +31,6 @@ exports.handler = handler(async (event, _ctx, user) => {
|
||||||
|
|
||||||
// POST /pos/import
|
// POST /pos/import
|
||||||
if (method === "POST" && id === "import") return bulkImport(event, user);
|
if (method === "POST" && id === "import") return bulkImport(event, user);
|
||||||
// GET /pos/dynamo-scan
|
|
||||||
if (method === "GET" && id === "dynamo-scan") return dynamoScan(event, user);
|
|
||||||
|
|
||||||
if (!id) {
|
if (!id) {
|
||||||
if (method === "GET") return listPOs(qs, user);
|
if (method === "GET") return listPOs(qs, user);
|
||||||
|
|
@ -48,12 +45,94 @@ exports.handler = handler(async (event, _ctx, user) => {
|
||||||
return { statusCode: 405, body: JSON.stringify({ error: "Method Not Allowed" }) };
|
return { statusCode: 405, body: JSON.stringify({ error: "Method Not Allowed" }) };
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ─── Auto-Sync from External purchase-orders Table ──────────────────────────
|
||||||
|
// Scans the external purchase-orders table and upserts any new POs into
|
||||||
|
// the internal ledgerflow-pos table. Runs before every list to keep in sync.
|
||||||
|
|
||||||
|
async function syncFromPurchaseOrders(db, user) {
|
||||||
|
const EXTERNAL = TABLES.PURCHASE_ORDERS;
|
||||||
|
const now = new Date().toISOString();
|
||||||
|
|
||||||
|
// Scan all items from the external table (paginate through all pages)
|
||||||
|
let externalItems = [];
|
||||||
|
let lastKey;
|
||||||
|
do {
|
||||||
|
const params = { TableName: EXTERNAL, ...(lastKey && { ExclusiveStartKey: lastKey }) };
|
||||||
|
const result = await db.send(new ScanCommand(params));
|
||||||
|
externalItems = externalItems.concat(result.Items || []);
|
||||||
|
lastKey = result.LastEvaluatedKey;
|
||||||
|
} while (lastKey);
|
||||||
|
|
||||||
|
if (externalItems.length === 0) return;
|
||||||
|
|
||||||
|
// Get all existing PO numbers to avoid duplicates
|
||||||
|
let existingNumbers = new Set();
|
||||||
|
let lek;
|
||||||
|
do {
|
||||||
|
const scan = await db.send(new ScanCommand({
|
||||||
|
TableName: TABLE,
|
||||||
|
ProjectionExpression: "poNumber",
|
||||||
|
...(lek && { ExclusiveStartKey: lek }),
|
||||||
|
}));
|
||||||
|
(scan.Items || []).forEach(i => existingNumbers.add(i.poNumber));
|
||||||
|
lek = scan.LastEvaluatedKey;
|
||||||
|
} while (lek);
|
||||||
|
|
||||||
|
// Insert any POs that don't already exist
|
||||||
|
const newItems = externalItems.filter(item => {
|
||||||
|
const poNumber = (item.po_number || item.poNumber || "").toString().trim();
|
||||||
|
return poNumber && !existingNumbers.has(poNumber);
|
||||||
|
});
|
||||||
|
|
||||||
|
const batchSize = 25;
|
||||||
|
for (let i = 0; i < newItems.length; i += batchSize) {
|
||||||
|
const batch = newItems.slice(i, i + batchSize);
|
||||||
|
await Promise.all(batch.map(async (raw) => {
|
||||||
|
try {
|
||||||
|
const poNumber = (raw.po_number || raw.poNumber || "").toString().trim();
|
||||||
|
const vendor = (raw.supplier?.name || raw.vendor_name || raw.vendor || "").toString().trim();
|
||||||
|
const amount = parseFloat(raw.total_amount || raw.amount || 0);
|
||||||
|
if (!poNumber || !vendor) return;
|
||||||
|
|
||||||
|
const firstLine = Array.isArray(raw.line_items) ? raw.line_items[0] : null;
|
||||||
|
|
||||||
|
const item = {
|
||||||
|
id: genId("PO"),
|
||||||
|
poNumber,
|
||||||
|
vendor,
|
||||||
|
amount,
|
||||||
|
billed: 0,
|
||||||
|
status: (raw.po_status || raw.status || "open").toLowerCase(),
|
||||||
|
issueDate: raw.order_date || raw.issue_date || raw.issueDate || now.split("T")[0],
|
||||||
|
dueDate: firstLine?.need_by || raw.due_date || raw.dueDate || null,
|
||||||
|
notes: firstLine?.description || raw.notes || raw.description || "",
|
||||||
|
source: "auto-sync",
|
||||||
|
createdBy: user?.email || "system",
|
||||||
|
createdAt: now,
|
||||||
|
updatedAt: now,
|
||||||
|
};
|
||||||
|
|
||||||
|
await db.send(new PutCommand({ TableName: TABLE, Item: item }));
|
||||||
|
} catch (err) {
|
||||||
|
console.warn("[auto-sync] skipped item:", err.message);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ─── List ─────────────────────────────────────────────────────────────────────
|
// ─── List ─────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
async function listPOs(qs, user) {
|
async function listPOs(qs, user) {
|
||||||
const { limit, cursor } = parsePagination(qs);
|
const { limit, cursor } = parsePagination(qs);
|
||||||
const db = getDocClient();
|
const db = getDocClient();
|
||||||
|
|
||||||
|
// Auto-sync new POs from external purchase-orders table
|
||||||
|
try {
|
||||||
|
await syncFromPurchaseOrders(db, user);
|
||||||
|
} catch (err) {
|
||||||
|
console.warn("[auto-sync] failed, returning cached POs:", err.message);
|
||||||
|
}
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
TableName: TABLE,
|
TableName: TABLE,
|
||||||
Limit: limit,
|
Limit: limit,
|
||||||
|
|
@ -238,48 +317,3 @@ async function bulkImport(event, user) {
|
||||||
return ok({ message: `Import complete`, ...results });
|
return ok({ message: `Import complete`, ...results });
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── Live DynamoDB Scan (Customer's Own Table) ───────────────────────────────
|
|
||||||
// Proxies a scan against the customer's configured DynamoDB table.
|
|
||||||
// The customer's table name/field config is stored in their settings.
|
|
||||||
|
|
||||||
async function dynamoScan(event, user) {
|
|
||||||
const qs = event.queryStringParameters || {};
|
|
||||||
const filterStatus = qs.status;
|
|
||||||
const limit = Math.min(parseInt(qs.limit || "50"), 200);
|
|
||||||
|
|
||||||
// Retrieve customer's DynamoDB config from the settings table
|
|
||||||
const db = getDocClient();
|
|
||||||
const settingsResult = await db.send(new GetCommand({ TableName: TABLES.SETTINGS, Key: { userId: user.userId } }));
|
|
||||||
const dynamoCfg = settingsResult.Item?.config?.dynamo;
|
|
||||||
|
|
||||||
if (!dynamoCfg?.table) return badRequest("No DynamoDB table configured — update your settings first");
|
|
||||||
|
|
||||||
const params = { TableName: dynamoCfg.table, Limit: limit };
|
|
||||||
|
|
||||||
if (filterStatus) {
|
|
||||||
params.FilterExpression = "#s = :s";
|
|
||||||
params.ExpressionAttributeNames = { "#s": "status" };
|
|
||||||
params.ExpressionAttributeValues = { ":s": filterStatus };
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const result = await db.send(new ScanCommand(params));
|
|
||||||
|
|
||||||
// Map customer's field names to LedgerFlow's expected shape
|
|
||||||
const fields = dynamoCfg.fields || {};
|
|
||||||
const items = (result.Items || []).map(item => ({
|
|
||||||
poNumber: item[fields.poNumber || "po_number"] || "",
|
|
||||||
vendor: item[fields.vendor || "vendor_name"] || "",
|
|
||||||
amount: parseFloat(item[fields.amount || "total_amount"]) || 0,
|
|
||||||
status: item[fields.status || "status"] || "open",
|
|
||||||
issueDate: item[fields.issueDate || "issue_date"] || "",
|
|
||||||
dueDate: item[fields.dueDate || "due_date"] || "",
|
|
||||||
_raw: item,
|
|
||||||
}));
|
|
||||||
|
|
||||||
return ok({ items, count: result.Count });
|
|
||||||
} catch (err) {
|
|
||||||
if (err.name === "ResourceNotFoundException") return notFound(`Table ${dynamoCfg.table}`);
|
|
||||||
return serverError(`DynamoDB scan failed: ${err.message}`, err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,10 @@
|
||||||
"deploy": "cd infra && npx aws-cdk deploy --all",
|
"deploy": "cd infra && npx aws-cdk deploy --all",
|
||||||
"deploy:dev": "cd infra && npx aws-cdk deploy --all --context env=dev",
|
"deploy:dev": "cd infra && npx aws-cdk deploy --all --context env=dev",
|
||||||
"destroy": "cd infra && npx aws-cdk destroy --all",
|
"destroy": "cd infra && npx aws-cdk destroy --all",
|
||||||
"test": "jest --passWithNoTests"
|
"test": "jest --passWithNoTests",
|
||||||
|
"local": "sam local start-api --env-vars env.local.json --warm-containers EAGER --port 3001",
|
||||||
|
"local:build": "sam build",
|
||||||
|
"local:invoke": "sam local invoke --env-vars env.local.json"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/aws-lambda": "^8.10.136",
|
"@types/aws-lambda": "^8.10.136",
|
||||||
|
|
|
||||||
|
|
@ -112,11 +112,12 @@ function getDocClient() {
|
||||||
// ─── Table Names ─────────────────────────────────────────────────────────────
|
// ─── Table Names ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
const TABLES = {
|
const TABLES = {
|
||||||
POS: process.env.POS_TABLE || "ledgerflow-pos",
|
POS: process.env.POS_TABLE || "ledgerflow-pos",
|
||||||
INVOICES: process.env.INVOICES_TABLE || "ledgerflow-invoices",
|
PURCHASE_ORDERS: process.env.PURCHASE_ORDERS_TABLE || "purchase-orders",
|
||||||
EDI_TX: process.env.EDI_TX_TABLE || "ledgerflow-edi-transactions",
|
INVOICES: process.env.INVOICES_TABLE || "ledgerflow-invoices",
|
||||||
SESSIONS: process.env.SESSIONS_TABLE || "ledgerflow-sessions",
|
EDI_TX: process.env.EDI_TX_TABLE || "ledgerflow-edi-transactions",
|
||||||
SETTINGS: process.env.SETTINGS_TABLE || "ledgerflow-settings",
|
SESSIONS: process.env.SESSIONS_TABLE || "ledgerflow-sessions",
|
||||||
|
SETTINGS: process.env.SETTINGS_TABLE || "ledgerflow-settings",
|
||||||
};
|
};
|
||||||
|
|
||||||
// ─── Pagination Helper ───────────────────────────────────────────────────────
|
// ─── Pagination Helper ───────────────────────────────────────────────────────
|
||||||
|
|
|
||||||
277
template.yaml
Normal file
277
template.yaml
Normal file
|
|
@ -0,0 +1,277 @@
|
||||||
|
AWSTemplateFormatVersion: "2010-09-09"
|
||||||
|
Transform: AWS::Serverless-2016-10-31
|
||||||
|
Description: LedgerFlow B2B Accounting — local SAM development
|
||||||
|
|
||||||
|
Globals:
|
||||||
|
Function:
|
||||||
|
Runtime: nodejs20.x
|
||||||
|
Architectures: [arm64]
|
||||||
|
MemorySize: 512
|
||||||
|
Timeout: 30
|
||||||
|
Environment:
|
||||||
|
Variables:
|
||||||
|
NODE_ENV: dev
|
||||||
|
AWS_NODEJS_CONNECTION_REUSE_ENABLED: "1"
|
||||||
|
POS_TABLE: ledgerflow-pos
|
||||||
|
INVOICES_TABLE: ledgerflow-invoices
|
||||||
|
EDI_TX_TABLE: ledgerflow-edi-transactions
|
||||||
|
SESSIONS_TABLE: ledgerflow-sessions
|
||||||
|
SETTINGS_TABLE: ledgerflow-settings
|
||||||
|
PURCHASE_ORDERS_TABLE: purchase-orders
|
||||||
|
EDI_INPUT_BUCKET: !Sub "ledgerflow-edi-input-${AWS::AccountId}"
|
||||||
|
EDI_OUTPUT_BUCKET: !Sub "ledgerflow-edi-output-${AWS::AccountId}"
|
||||||
|
GOOGLE_CLIENT_ID: ""
|
||||||
|
ALLOWED_ORIGIN: "*"
|
||||||
|
ALLOWED_DOMAINS: ""
|
||||||
|
EDI_PARTNERSHIP_ID: ""
|
||||||
|
EDI_TRANSFORMER_ID: ""
|
||||||
|
EDI_SENDER_ID: ""
|
||||||
|
EDI_RECEIVER_ID: ""
|
||||||
|
|
||||||
|
Resources:
|
||||||
|
# ── API Gateway ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
LedgerFlowAPI:
|
||||||
|
Type: AWS::Serverless::HttpApi
|
||||||
|
Properties:
|
||||||
|
StageName: $default
|
||||||
|
CorsConfiguration:
|
||||||
|
AllowOrigins:
|
||||||
|
- "*"
|
||||||
|
- "http://localhost:3000"
|
||||||
|
AllowMethods:
|
||||||
|
- GET
|
||||||
|
- POST
|
||||||
|
- PUT
|
||||||
|
- PATCH
|
||||||
|
- DELETE
|
||||||
|
- OPTIONS
|
||||||
|
AllowHeaders:
|
||||||
|
- Content-Type
|
||||||
|
- Authorization
|
||||||
|
MaxAge: 86400
|
||||||
|
Auth:
|
||||||
|
DefaultAuthorizer: GoogleJWT
|
||||||
|
Authorizers:
|
||||||
|
GoogleJWT:
|
||||||
|
AuthorizationScopes: []
|
||||||
|
FunctionArn: !GetAtt AuthorizerFn.Arn
|
||||||
|
FunctionInvokeRole: !GetAtt AuthorizerInvokeRole.Arn
|
||||||
|
Identity:
|
||||||
|
Headers:
|
||||||
|
- Authorization
|
||||||
|
AuthorizerPayloadFormatVersion: "2.0"
|
||||||
|
EnableSimpleResponses: true
|
||||||
|
|
||||||
|
# IAM role allowing API Gateway to invoke the authorizer Lambda
|
||||||
|
AuthorizerInvokeRole:
|
||||||
|
Type: AWS::IAM::Role
|
||||||
|
Properties:
|
||||||
|
AssumeRolePolicyDocument:
|
||||||
|
Version: "2012-10-17"
|
||||||
|
Statement:
|
||||||
|
- Effect: Allow
|
||||||
|
Principal:
|
||||||
|
Service: apigateway.amazonaws.com
|
||||||
|
Action: sts:AssumeRole
|
||||||
|
Policies:
|
||||||
|
- PolicyName: InvokeAuthorizerFn
|
||||||
|
PolicyDocument:
|
||||||
|
Version: "2012-10-17"
|
||||||
|
Statement:
|
||||||
|
- Effect: Allow
|
||||||
|
Action: lambda:InvokeFunction
|
||||||
|
Resource: !GetAtt AuthorizerFn.Arn
|
||||||
|
|
||||||
|
# ── Lambda Functions ─────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
AuthorizerFn:
|
||||||
|
Type: AWS::Serverless::Function
|
||||||
|
Properties:
|
||||||
|
FunctionName: ledgerflow-authorizer
|
||||||
|
Handler: index.handler
|
||||||
|
CodeUri: lambdas/authorizer/
|
||||||
|
Metadata:
|
||||||
|
BuildMethod: esbuild
|
||||||
|
BuildProperties:
|
||||||
|
Minify: false
|
||||||
|
Sourcemap: true
|
||||||
|
EntryPoints: [index.js]
|
||||||
|
External: []
|
||||||
|
|
||||||
|
AuthFn:
|
||||||
|
Type: AWS::Serverless::Function
|
||||||
|
Properties:
|
||||||
|
FunctionName: ledgerflow-auth
|
||||||
|
Handler: index.handler
|
||||||
|
CodeUri: lambdas/auth/
|
||||||
|
Events:
|
||||||
|
AuthConfig:
|
||||||
|
Type: HttpApi
|
||||||
|
Properties:
|
||||||
|
ApiId: !Ref LedgerFlowAPI
|
||||||
|
Path: /auth/config
|
||||||
|
Method: ANY
|
||||||
|
Auth:
|
||||||
|
Authorizer: NONE
|
||||||
|
AuthConfigProxy:
|
||||||
|
Type: HttpApi
|
||||||
|
Properties:
|
||||||
|
ApiId: !Ref LedgerFlowAPI
|
||||||
|
Path: /auth/config/{proxy+}
|
||||||
|
Method: ANY
|
||||||
|
Auth:
|
||||||
|
Authorizer: NONE
|
||||||
|
AuthMe:
|
||||||
|
Type: HttpApi
|
||||||
|
Properties:
|
||||||
|
ApiId: !Ref LedgerFlowAPI
|
||||||
|
Path: /auth/me
|
||||||
|
Method: ANY
|
||||||
|
Auth:
|
||||||
|
Authorizer: NONE
|
||||||
|
AuthMeProxy:
|
||||||
|
Type: HttpApi
|
||||||
|
Properties:
|
||||||
|
ApiId: !Ref LedgerFlowAPI
|
||||||
|
Path: /auth/me/{proxy+}
|
||||||
|
Method: ANY
|
||||||
|
Auth:
|
||||||
|
Authorizer: NONE
|
||||||
|
AuthLogout:
|
||||||
|
Type: HttpApi
|
||||||
|
Properties:
|
||||||
|
ApiId: !Ref LedgerFlowAPI
|
||||||
|
Path: /auth/logout
|
||||||
|
Method: ANY
|
||||||
|
Auth:
|
||||||
|
Authorizer: NONE
|
||||||
|
AuthLogoutProxy:
|
||||||
|
Type: HttpApi
|
||||||
|
Properties:
|
||||||
|
ApiId: !Ref LedgerFlowAPI
|
||||||
|
Path: /auth/logout/{proxy+}
|
||||||
|
Method: ANY
|
||||||
|
Auth:
|
||||||
|
Authorizer: NONE
|
||||||
|
Metadata:
|
||||||
|
BuildMethod: esbuild
|
||||||
|
BuildProperties:
|
||||||
|
Minify: false
|
||||||
|
Sourcemap: true
|
||||||
|
EntryPoints: [index.js]
|
||||||
|
External: []
|
||||||
|
|
||||||
|
POsFn:
|
||||||
|
Type: AWS::Serverless::Function
|
||||||
|
Properties:
|
||||||
|
FunctionName: ledgerflow-pos
|
||||||
|
Handler: index.handler
|
||||||
|
CodeUri: lambdas/pos/
|
||||||
|
Events:
|
||||||
|
POs:
|
||||||
|
Type: HttpApi
|
||||||
|
Properties:
|
||||||
|
ApiId: !Ref LedgerFlowAPI
|
||||||
|
Path: /pos
|
||||||
|
Method: ANY
|
||||||
|
POsProxy:
|
||||||
|
Type: HttpApi
|
||||||
|
Properties:
|
||||||
|
ApiId: !Ref LedgerFlowAPI
|
||||||
|
Path: /pos/{proxy+}
|
||||||
|
Method: ANY
|
||||||
|
Metadata:
|
||||||
|
BuildMethod: esbuild
|
||||||
|
BuildProperties:
|
||||||
|
Minify: false
|
||||||
|
Sourcemap: true
|
||||||
|
EntryPoints: [index.js]
|
||||||
|
External: []
|
||||||
|
|
||||||
|
InvoicesFn:
|
||||||
|
Type: AWS::Serverless::Function
|
||||||
|
Properties:
|
||||||
|
FunctionName: ledgerflow-invoices
|
||||||
|
Handler: index.handler
|
||||||
|
CodeUri: lambdas/invoices/
|
||||||
|
Events:
|
||||||
|
Invoices:
|
||||||
|
Type: HttpApi
|
||||||
|
Properties:
|
||||||
|
ApiId: !Ref LedgerFlowAPI
|
||||||
|
Path: /invoices
|
||||||
|
Method: ANY
|
||||||
|
InvoicesProxy:
|
||||||
|
Type: HttpApi
|
||||||
|
Properties:
|
||||||
|
ApiId: !Ref LedgerFlowAPI
|
||||||
|
Path: /invoices/{proxy+}
|
||||||
|
Method: ANY
|
||||||
|
Metadata:
|
||||||
|
BuildMethod: esbuild
|
||||||
|
BuildProperties:
|
||||||
|
Minify: false
|
||||||
|
Sourcemap: true
|
||||||
|
EntryPoints: [index.js]
|
||||||
|
External: []
|
||||||
|
|
||||||
|
EDIFn:
|
||||||
|
Type: AWS::Serverless::Function
|
||||||
|
Properties:
|
||||||
|
FunctionName: ledgerflow-edi
|
||||||
|
Handler: index.handler
|
||||||
|
CodeUri: lambdas/edi/
|
||||||
|
Timeout: 60
|
||||||
|
Events:
|
||||||
|
EDI:
|
||||||
|
Type: HttpApi
|
||||||
|
Properties:
|
||||||
|
ApiId: !Ref LedgerFlowAPI
|
||||||
|
Path: /edi
|
||||||
|
Method: ANY
|
||||||
|
EDIProxy:
|
||||||
|
Type: HttpApi
|
||||||
|
Properties:
|
||||||
|
ApiId: !Ref LedgerFlowAPI
|
||||||
|
Path: /edi/{proxy+}
|
||||||
|
Method: ANY
|
||||||
|
Metadata:
|
||||||
|
BuildMethod: esbuild
|
||||||
|
BuildProperties:
|
||||||
|
Minify: false
|
||||||
|
Sourcemap: true
|
||||||
|
EntryPoints: [index.js]
|
||||||
|
External: []
|
||||||
|
|
||||||
|
SettingsFn:
|
||||||
|
Type: AWS::Serverless::Function
|
||||||
|
Properties:
|
||||||
|
FunctionName: ledgerflow-settings
|
||||||
|
Handler: index.handler
|
||||||
|
CodeUri: lambdas/settings/
|
||||||
|
Events:
|
||||||
|
Settings:
|
||||||
|
Type: HttpApi
|
||||||
|
Properties:
|
||||||
|
ApiId: !Ref LedgerFlowAPI
|
||||||
|
Path: /settings
|
||||||
|
Method: ANY
|
||||||
|
SettingsProxy:
|
||||||
|
Type: HttpApi
|
||||||
|
Properties:
|
||||||
|
ApiId: !Ref LedgerFlowAPI
|
||||||
|
Path: /settings/{proxy+}
|
||||||
|
Method: ANY
|
||||||
|
Metadata:
|
||||||
|
BuildMethod: esbuild
|
||||||
|
BuildProperties:
|
||||||
|
Minify: false
|
||||||
|
Sourcemap: true
|
||||||
|
EntryPoints: [index.js]
|
||||||
|
External: []
|
||||||
|
|
||||||
|
Outputs:
|
||||||
|
ApiUrl:
|
||||||
|
Description: Local API Gateway endpoint
|
||||||
|
Value: !Sub "https://${LedgerFlowAPI}.execute-api.${AWS::Region}.amazonaws.com"
|
||||||
Loading…
Add table
Reference in a new issue