{
  "updatedAt": "2026-07-02T05:50:32.416Z",
  "createdAt": "2026-07-01T11:43:03.254Z",
  "id": "pir7gSxbE9mfixPc",
  "name": "\ub124\uc774\ubc84 \uc140\ub7ec \uc790\ub3d9\ud654 - \uc1a1\uc7a5/\ubc1c\uc1a1\ucc98\ub9ac (dispatch)",
  "description": null,
  "active": true,
  "isArchived": false,
  "nodes": [
    {
      "parameters": {},
      "id": "f1b5f9c1-7c4e-4939-af06-2440ecb243e4",
      "name": "Manual Trigger",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        224,
        176
      ]
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "50 * * * *"
            }
          ]
        }
      },
      "id": "23b64bba-feb8-450c-924a-090bc085721f",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.3,
      "position": [
        224,
        400
      ]
    },
    {
      "parameters": {
        "jsCode": "const bcrypt = require('bcryptjs');\nconst axios = require('axios');\nconst ID = $env.NAVER_CLIENT_ID, SECRET = $env.NAVER_CLIENT_SECRET;\nif (!ID || !SECRET) throw new Error('\ub124\uc774\ubc84 \ud0a4 \uc5c6\uc74c: NAVER_CLIENT_ID / NAVER_CLIENT_SECRET env \ud655\uc778');\nconst ts = Date.now();\nconst sign = Buffer.from(bcrypt.hashSync(ID + '_' + ts, SECRET)).toString('base64');\nconst body = 'client_id=' + encodeURIComponent(ID) + '&timestamp=' + ts + '&client_secret_sign=' + encodeURIComponent(sign) + '&grant_type=client_credentials&type=SELF';\nconst res = await axios.post('https://api.commerce.naver.com/external/v1/oauth2/token', body, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } });\nreturn [{ json: { token: res.data.access_token } }];"
      },
      "id": "b39f4ebe-a56e-4482-a2dd-5edf52a201ab",
      "name": "\ub124\uc774\ubc84 \ud1a0\ud070 \ubc1c\uae09",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        448,
        288
      ]
    },
    {
      "parameters": {
        "endpoint": "={{ $env.GRAPHQL_URL }}",
        "query": "query { orders(first: 100, filter: { deliveryStatus: [TRACKING_DELIVERY], type: [BY_STAFF_FOR_BAD_STOCK] }, sortBy: { direction: DESC, field: NUMBER }) { edges { node { etcInfo fulfillments { trackingNumber courier { codeGoodsflow } lines { orderLine { variant { sku } } } } } } } }",
        "headerParametersUi": {
          "parameter": [
            {
              "name": "Authorization",
              "value": "={{ $env.AUTH_TOKEN }}"
            }
          ]
        }
      },
      "id": "67f58db1-4ff3-434b-8ad8-c445bb8dfac2",
      "name": "Saleor \ucd9c\uace0\uc8fc\ubb38 \uc870\ud68c",
      "type": "n8n-nodes-base.graphql",
      "typeVersion": 1.1,
      "position": [
        672,
        288
      ]
    },
    {
      "parameters": {
        "jsCode": "const edges = ((($input.first().json || {}).data || {}).orders || {}).edges || [];\nconst EXCLUDED = new Set(['POJANGBOSS', 'COUPANG', '']);   // \uc790\uccb4\ubc30\uc1a1/\ub85c\ucf13/\ubbf8\uc0c1 \uc81c\uc678\nconst trackMap = {};   // 'orderId||sku' -> { trackingNumber, courierCode }\nconst orderIds = new Set();\nfor (const e of edges) {\n  const n = e.node; const et = n.etcInfo || {};\n  if (et.open_mall_name !== '\ub124\uc774\ubc84') continue;            // \ub124\uc774\ubc84 \uc8fc\ubb38\ub9cc\n  const omn = et.open_mall_order_number != null ? String(et.open_mall_order_number) : '';\n  if (!omn) continue;\n  for (const f of (n.fulfillments || [])) {\n    if (!f.trackingNumber) continue;\n    const code = (f.courier && f.courier.codeGoodsflow) || '';\n    if (EXCLUDED.has(code)) continue;\n    const tn = String(f.trackingNumber).replace(/[^0-9]/g, '');\n    if (tn.length < 10) continue;                          // placeholder \uc1a1\uc7a5 \uc81c\uc678\n    for (const ln of (f.lines || [])) {\n      const sku = ln.orderLine && ln.orderLine.variant && ln.orderLine.variant.sku;\n      if (!sku) continue;\n      if (!trackMap[omn + '||' + sku]) trackMap[omn + '||' + sku] = { trackingNumber: tn, courierCode: code };\n      orderIds.add(omn);\n    }\n  }\n}\nif (orderIds.size === 0) return [];\nreturn [{ json: { trackMap, orderIds: [...orderIds] } }];"
      },
      "id": "6009485d-cff4-4968-b458-d1830ca70c56",
      "name": "\uc1a1\uc7a5\ub9f5 \uc0dd\uc131",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        896,
        288
      ]
    },
    {
      "parameters": {
        "jsCode": "const axios = require('axios');\nconst token = $('\ub124\uc774\ubc84 \ud1a0\ud070 \ubc1c\uae09').first().json.token;\nconst orderIds = ($input.first().json.orderIds) || [];\nif (orderIds.length === 0) return [];\nconst productOrderIds = [];\nconst poToOrder = {};\nfor (const oid of orderIds) {\n  try {\n    const r = await axios.get('https://api.commerce.naver.com/external/v1/pay-order/seller/orders/' + oid + '/product-order-ids', { headers: { Authorization: 'Bearer ' + token } });\n    for (const p of ((r.data || {}).data || [])) { productOrderIds.push(String(p)); poToOrder[String(p)] = oid; }\n  } catch (e) { console.log('[\ubc1c\uc1a1] product-order-ids \uc2e4\ud328 ' + oid + ': ' + (e.response ? e.response.status : e.message)); }\n}\nif (productOrderIds.length === 0) return [];\nreturn [{ json: { productOrderIds, poToOrder } }];"
      },
      "id": "47c4e21e-1d8d-4bb4-bb8e-3e783d17ef4f",
      "name": "productOrderId \uc870\ud68c",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1104,
        288
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.commerce.naver.com/external/v1/pay-order/seller/product-orders/query",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "={{ \"Bearer \" + $('\ub124\uc774\ubc84 \ud1a0\ud070 \ubc1c\uae09').first().json.token }}"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ { \"productOrderIds\": $json.productOrderIds } }}",
        "options": {}
      },
      "id": "8c4d9543-093d-46c4-a221-c5fb542e02cc",
      "name": "\uc0c1\ud488\uc8fc\ubb38 \uc0c1\uc138\uc870\ud68c",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1328,
        288
      ]
    },
    {
      "parameters": {
        "jsCode": "const rows = (($input.first().json || {}).data) || [];\nconst trackMap = ($('\uc1a1\uc7a5\ub9f5 \uc0dd\uc131').first().json.trackMap) || {};\nconst poToOrder = ($('productOrderId \uc870\ud68c').first().json.poToOrder) || {};\nconst nowKst = new Date(Date.now() + 9 * 3600 * 1000).toISOString().replace('Z', '+09:00');\n\nconst contents = [];\nconst skipped = [];\nfor (const it of rows) {\n  const po = it.productOrder || {};\n  const oid = poToOrder[String(po.productOrderId)] || String((it.order || {}).orderId);\n  // \ubc1c\uc1a1 \ub300\uc0c1: \uacb0\uc81c\uc644\ub8cc + \ubc1c\uc8fc\ud655\uc778\ub428(OK) + \ud0dd\ubc30\n  if (po.productOrderStatus !== 'PAYED') continue;\n  if (po.placeOrderStatus !== 'OK') continue;\n  if (po.expectedDeliveryMethod !== 'DELIVERY') continue;\n  const m = trackMap[oid + '||' + po.sellerProductCode];\n  if (!m) { skipped.push({ productOrderId: String(po.productOrderId), oid, sku: po.sellerProductCode }); continue; }\n  contents.push({ productOrderId: String(po.productOrderId), deliveryMethod: 'DELIVERY', deliveryCompanyCode: m.courierCode, trackingNumber: m.trackingNumber, dispatchDate: nowKst });\n}\nif (skipped.length) console.log('[\ubc1c\uc1a1] \uc1a1\uc7a5\ub9e4\uce6d \uc5c6\uc74c ' + skipped.length + '\uac74: ' + JSON.stringify(skipped.slice(0, 30)));\nif (contents.length === 0) return [];\nreturn [{ json: { dispatchProductOrders: contents } }];"
      },
      "id": "4f2713c5-4fda-4793-811a-69c6d5654628",
      "name": "\ubc1c\uc1a1 payload \uc0dd\uc131",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1552,
        288
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.commerce.naver.com/external/v1/pay-order/seller/product-orders/dispatch",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "={{ \"Bearer \" + $('\ub124\uc774\ubc84 \ud1a0\ud070 \ubc1c\uae09').first().json.token }}"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ { \"dispatchProductOrders\": $json.dispatchProductOrders } }}",
        "options": {}
      },
      "id": "dd996ec0-4810-40f4-b2c5-4a9a73572040",
      "name": "\ubc1c\uc1a1\ucc98\ub9ac(dispatch)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1776,
        288
      ]
    },
    {
      "parameters": {
        "jsCode": "const d = (($input.first().json || {}).data) || {};\nconst ok = (d.successProductOrderIds || []).length;\nconst fail = d.failProductOrderInfos || [];\nif (fail.length) console.log('[\ubc1c\uc1a1\ucc98\ub9ac] \uc2e4\ud328 ' + fail.length + '\uac74: ' + JSON.stringify(fail));\nreturn [{ json: { dispatched: ok, failed: fail.length } }];"
      },
      "id": "19405d23-25e6-4307-a55c-7851b68cd2de",
      "name": "\ubc1c\uc1a1\uacb0\uacfc \ud655\uc778",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1984,
        288
      ]
    }
  ],
  "connections": {
    "Manual Trigger": {
      "main": [
        [
          {
            "node": "\ub124\uc774\ubc84 \ud1a0\ud070 \ubc1c\uae09",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "\ub124\uc774\ubc84 \ud1a0\ud070 \ubc1c\uae09",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ub124\uc774\ubc84 \ud1a0\ud070 \ubc1c\uae09": {
      "main": [
        [
          {
            "node": "Saleor \ucd9c\uace0\uc8fc\ubb38 \uc870\ud68c",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Saleor \ucd9c\uace0\uc8fc\ubb38 \uc870\ud68c": {
      "main": [
        [
          {
            "node": "\uc1a1\uc7a5\ub9f5 \uc0dd\uc131",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\uc1a1\uc7a5\ub9f5 \uc0dd\uc131": {
      "main": [
        [
          {
            "node": "productOrderId \uc870\ud68c",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "productOrderId \uc870\ud68c": {
      "main": [
        [
          {
            "node": "\uc0c1\ud488\uc8fc\ubb38 \uc0c1\uc138\uc870\ud68c",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\uc0c1\ud488\uc8fc\ubb38 \uc0c1\uc138\uc870\ud68c": {
      "main": [
        [
          {
            "node": "\ubc1c\uc1a1 payload \uc0dd\uc131",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ubc1c\uc1a1 payload \uc0dd\uc131": {
      "main": [
        [
          {
            "node": "\ubc1c\uc1a1\ucc98\ub9ac(dispatch)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ubc1c\uc1a1\ucc98\ub9ac(dispatch)": {
      "main": [
        [
          {
            "node": "\ubc1c\uc1a1\uacb0\uacfc \ud655\uc778",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "staticData": {
    "node:Schedule Trigger": {
      "recurrenceRules": []
    }
  },
  "meta": null,
  "versionId": "5579e10b-1cad-40bd-a50b-2eb21c8a23b3",
  "activeVersionId": "5579e10b-1cad-40bd-a50b-2eb21c8a23b3",
  "versionCounter": 17,
  "triggerCount": 1,
  "tags": [],
  "shared": [
    {
      "updatedAt": "2026-07-01T11:43:03.260Z",
      "createdAt": "2026-07-01T11:43:03.260Z",
      "role": "workflow:owner",
      "workflowId": "pir7gSxbE9mfixPc",
      "projectId": "PyrRNJYltDksNq22",
      "project": {
        "updatedAt": "2025-12-17T00:26:00.367Z",
        "createdAt": "2025-12-17T00:18:19.940Z",
        "id": "PyrRNJYltDksNq22",
        "name": "\ub3c4\ud604 \uae40 <dev-do@naver.com>",
        "type": "personal",
        "icon": null,
        "description": null
      }
    }
  ]
}