Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
c684c39
feat(orocommerce): allow to install activepieces to subfolder of the …
x86demon Feb 27, 2026
043051b
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon Mar 3, 2026
96fa173
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon Mar 3, 2026
48e414c
Merge branch 'activepieces:main' into poc/orocommerce_prefixed-path-i…
x86demon Mar 3, 2026
8cc7ebf
Merge branch 'poc/orocommerce' into poc/orocommerce_prefixed-path-ins…
x86demon Mar 10, 2026
5d33749
Merge branch 'poc/orocommerce_prefixed-path-install' of github.com:x8…
x86demon Mar 10, 2026
2cd8dd5
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon Mar 10, 2026
114c824
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon Mar 11, 2026
ba3aeb5
feat(orocommerce): subfolder-install fixes for 0.79+
x86demon Mar 11, 2026
7b1b7a7
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon Mar 11, 2026
9c2d4ed
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon Mar 17, 2026
b2ab3d7
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon Mar 19, 2026
ad4057b
feat(orocommerce): subfolder installation fixes
x86demon Mar 19, 2026
d482aab
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon Mar 19, 2026
e336464
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon Mar 19, 2026
29b3dc2
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon Mar 20, 2026
5d6e037
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon Mar 27, 2026
607c4b6
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon Apr 9, 2026
af07879
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon Apr 9, 2026
2edec15
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon Apr 10, 2026
c9f9ea9
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon Apr 29, 2026
db490f2
feat(orocommerce): updated base
x86demon Apr 29, 2026
d437167
feat(orocommerce): updated api
x86demon Apr 30, 2026
3a80db5
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon Apr 30, 2026
661e95a
feat(orocommerce): updated base
x86demon Apr 30, 2026
01015b0
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon May 5, 2026
ff83825
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon May 6, 2026
a06c728
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon May 6, 2026
0f97d3c
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon May 11, 2026
d957eb4
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon May 13, 2026
768a00c
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon May 13, 2026
76f9a80
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon May 15, 2026
2cf00c2
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon May 18, 2026
124abf0
feat(orocommerce): customized docker
x86demon May 19, 2026
fc8ceff
feat(orocommerce): subfolder install and Docker
x86demon May 20, 2026
e53030d
feat(orocommerce): subfolder install and Docker
x86demon May 20, 2026
84a206e
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon May 21, 2026
0ae3312
feat(orocommerce): subfolder install and Docker
x86demon May 21, 2026
2e1c925
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon May 21, 2026
0cfb944
feat(orocommerce): update doc
x86demon May 25, 2026
e795f37
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon May 25, 2026
13b2b05
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon May 27, 2026
08e1b3c
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon May 27, 2026
aefc7d9
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon May 28, 2026
a3aa886
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon May 28, 2026
f43f880
OPI-1597: Create CI build for activepieces
dubrsl Jun 7, 2026
828874d
feat(ci): add latest tag creation for Docker images on main branch su…
dubrsl Jun 7, 2026
4e0c678
feat(ci): update image tagging logic for Docker builds
dubrsl Jun 7, 2026
64081d7
feat(ci): enhance image tag formatting in Jenkinsfile
dubrsl Jun 7, 2026
ff22d46
feat(ci): ensure concurrent builds are disabled in Jenkins pipeline
dubrsl Jun 7, 2026
52ba732
feat(orocommerce): added orocommerce piece to requirements
x86demon Jun 9, 2026
5555ffe
feat(env): update .env.example and add .env.oro.example for configura…
dubrsl Jun 12, 2026
83534b3
Merge pull request #2 from oroinc/ticket/OPI-1597
dubrsl Jun 12, 2026
89f77ab
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon Jun 16, 2026
5ffa87c
feat(orocommerce): update .env.oro.example
x86demon Jun 18, 2026
0dfa0c6
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon Jun 18, 2026
0ffa297
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon Jun 22, 2026
842ca73
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon Jun 22, 2026
7b7995c
feat(orocommerce): added orocommerce SKILL for actions creation
x86demon Jun 22, 2026
3afd96f
feat(orocommerce): update .env.oro.example
x86demon Jun 26, 2026
9a72ec6
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon Jun 26, 2026
33a8c47
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon Jun 26, 2026
cb8d46c
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon Jul 20, 2026
f26a5e0
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon Jul 20, 2026
2590424
feat(orocommerce): embed-ce upgrade to match the latest codebase
x86demon Jul 20, 2026
b43d99b
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon Jul 27, 2026
2dcf9f0
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon Aug 3, 2026
fd5cf3a
feat(orocommerce): host mapping and skill
x86demon Aug 5, 2026
c55996b
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon Aug 5, 2026
e764953
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon Aug 7, 2026
502fd58
Merge remote-tracking branch 'origin/poc/orocommerce' into poc/orocom…
x86demon Aug 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
304 changes: 304 additions & 0 deletions .agents/skills/orocommerce-action-builder/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,304 @@
---
name: orocommerce-action-builder
description: Creates new OroCommerce piece actions from an OpenAPI specification. Use when the user asks to add a create/update/delete action to the OroCommerce piece, or provides an OpenAPI/Swagger spec for an OroCommerce resource endpoint.
---

# OroCommerce Action Builder

Build OroCommerce actions from an OpenAPI spec with minimum reading.
**Piece root:** `packages/pieces/community/orocommerce/src/`

## Decision tree

```
Spec provided?
YES → Step 1: Parse spec
NO → Ask for the OpenAPI YAML/JSON or the resource name so you can consult the spec
```

---

## Step 1 — Parse the spec (read only what you need)

From the spec extract:

| Item | Where to find it |
|---|---|
| Resource name (JSON:API `type`) | `POST /admin/api/{resource}` → `requestBody` → `data.type` |
| Create attributes | `POST` body schema → `data.attributes` properties |
| Update attributes | `PATCH /admin/api/{resource}/{id}` body → `data.attributes` |
| Relationships (create) | `POST` body → `data.relationships` keys + each `data.type` |
| Relationships (update) | `PATCH` body → `data.relationships` keys + each `data.type` |
| Required fields | `POST` body `required` array or spec description ("Example:" block is usually the minimum viable payload) |

> **Shortcut:** the spec description for `POST` and `PATCH` always contains a literal JSON example. Read that example — it shows every required field and the exact relationship type strings. Ignore all other spec noise.

---

## Step 2 — Map attributes → `Property` types

| Attribute characteristic | `Property` type |
|---|---|
| Short string (name, code, email, username, title) | `Property.ShortText` |
| Long string (description, notes, body) | `Property.LongText` |
| Date string (`YYYY-MM-DD`) | `Property.ShortText` with description `"YYYY-MM-DD format"` |
| Boolean flag (enabled, confirmed, locked) | `Property.Checkbox` |
| Numeric string passed as-is | `Property.ShortText` |
| JSON sub-object / freeform map | `Property.Json` |
| Enum with known values | `Property.StaticDropdown` listing the values |

Required on create → `required: true`. Optional → `required: false`.
On **update** actions every attribute is `required: false` (only provided fields are patched).

---

## Step 3 — Map relationships → dropdowns + `buildRels`

Each relationship in the spec has a `type` string (e.g. `"businessunits"`, `"userroles"`). Use this table to pick the right dropdown and `buildRels` entry:

| JSON:API `type` | Dropdown to use | `buildRels` call |
|---|---|---|
| `organizations` (single) | `organizationDropdown` | `organization: ['organizations', p.organization]` |
| `organizations` (multi) | `organizationsDropdown` | `organizations: ['organizations', p.organizations, true]` |
| `businessunits` (single owner) | `businessUnitRequiredDropdown` (create) / `businessUnitDropdown` (update) | hard-coded: `owner: { data: { type: 'businessunits', id: p.owner ?? '' } }` |
| `businessunits` (multi) | `businessUnitDropdown` | `businessUnits: ['businessunits', p.businessUnits, true]` |
| `users` (owner/sales rep) | `userDropdown` | `owner: ['users', p.owner]` |
| `customers` (required) | `customerRequiredDropdown` | hard-coded: `customer: { data: { type: 'customers', id: p.customer ?? '' } }` |
| `customers` (optional) | `customerDropdown` | `customer: ['customers', p.customer]` |
| `websites` | `websiteDropdown` | `website: ['websites', p.website]` |
| `customeruserroles` | `customerUserRoleDropdown` | `userRoles: ['customeruserroles', p.userRoles, true]` |
| `userroles` | `userRoleDropdown` | `userRoles: ['userroles', p.userRoles, true]` |
| `usergroups` | `userGroupDropdown` | `groups: ['usergroups', p.groups, true]` |
| `userauthstatuses` | `userAuthStatusDropdown` | `auth_status: ['userauthstatuses', p.authStatus]` |
| `paymentterms` | `paymentTermDropdown` | `paymentTerm: ['paymentterms', p.paymentTerm]` |
| `warehouses` | `warehouseDropdown` | `warehouse: ['warehouses', p.warehouse]` |
| `products` | `productDropdown` | `product: ['products', p.product]` |
| `customergroups` | `customerGroupDropdown` | `group: ['customergroups', p.group]` |
| `customertaxcodes` | `customerTaxCodeDropdown` | `taxCode: ['customertaxcodes', p.taxCode]` |
| `orderinternalstatuses` | `orderInternalStatusDropdown` | `internalStatus: ['orderinternalstatuses', p.internalStatus]` |
| `invoiceinternalstatuses` | `invoiceInternalStatusDropdown` | `internalStatus: ['invoiceinternalstatuses', p.internalStatus]` |
| Any unknown type | Add a new `makeSearchableDropdown` / `makeEnumDropdown` in `props.ts` | Same pattern |

**`many=true` rule:** use `true` as the third `buildRels` argument whenever the spec shows `"data": [...]` (array). Omit it (single) when spec shows `"data": {...}`.

---

## Step 4 — Add missing dropdowns (only if needed)

Check the **Existing dropdowns** table above. If the relationship type is already covered, import it — do not re-create it.

If a dropdown is missing, add it to `src/lib/common/props.ts` following the established patterns:

**Searchable (most relationships):**
```ts
export const myThingDropdown = makeSearchableDropdown({
displayName: 'My Thing',
description: 'Search my things by name.',
resourceUri: '/mythings', // JSON:API collection path
fieldsParam: 'id,name',
searchExpr: (q) => `name ~ "${q}"`,
labelFn: attrLabel('name'),
});
```

**Enum (status/code lists — small static sets):**
```ts
export const myStatusDropdown = makeEnumDropdown({
displayName: 'Status',
description: 'Select a status.',
resourceUri: '/mystatuses',
labelFn: attrLabel('name', 'id'), // fallback to id when name absent
});
```

Export the new dropdown from `src/lib/common/index.ts` via the existing `export * from './props'` — no extra line needed.

---

## Step 5 — Write the action files

### Create action template (`src/lib/actions/create-{resource}.ts`)

```ts
import { createAction, Property } from '@activepieces/pieces-framework';
import { HttpMethod } from '@activepieces/pieces-common';
import {
oroAuth, oroApiCall,
// ...dropdowns for this action...
additionalAttributesProp, additionalRelationsProp, additionalHeadersProp,
} from '../common';
import { OroAuth } from '../common/types';
import { jsonApiBodyUtils } from '../common/jsonapi-body-utils';

export const create{Resource}Action = createAction({
auth: oroAuth,
name: 'create_{resource}', // snake_case, permanent
displayName: 'Create {Resource}',
description: 'Creates a new {resource} record in OroCommerce.',
props: {
// --- Required attributes ---
fieldName: Property.ShortText({ displayName: 'Field Name', required: true }),

// --- Optional attributes ---
optField: Property.ShortText({ displayName: 'Optional Field', required: false }),

// --- Required relationships ---
owner: businessUnitRequiredDropdown, // if owner is required

// --- Optional relationships ---
organization: organizationDropdown,

additionalAttributes: additionalAttributesProp,
additionalRelations: additionalRelationsProp,
additionalHeaders: additionalHeadersProp,
},

async run(context) {
const p = context.propsValue;
const extraAttrs = jsonApiBodyUtils.parseAdditionalAttributes(p.additionalAttributes);
const extraRels = jsonApiBodyUtils.parseAdditionalRelations(p.additionalRelations);

const attributes = {
fieldName: p.fieldName, // required → always included
...jsonApiBodyUtils.pickDefined({ // optional → included only when non-null
optField: p.optField,
}),
...extraAttrs,
};

const relationships = {
owner: { data: { type: 'businessunits', id: p.owner ?? '' } }, // required rel
...jsonApiBodyUtils.buildRels({
organization: ['organizations', p.organization],
}),
...extraRels,
};

const response = await oroApiCall({
method: HttpMethod.POST,
resourceUri: '/{resources}',
auth: context.auth as OroAuth,
body: { data: { type: '{resources}', attributes, relationships } },
headers: p.additionalHeaders as Record<string, string>,
});

return response.body;
},
});
```

### Update action template (`src/lib/actions/update-{resource}.ts`)

Key differences from create:
- First prop is `{resource}Id: Property.ShortText({ required: true })` (the record to patch)
- Every attribute is `required: false`; wrap ALL in `jsonApiBodyUtils.pickDefined`
- Every relationship is optional — put all in `buildRels`, no hard-coded required rel
- HTTP method is `HttpMethod.PATCH`, URI is `/{resources}/${p.{resource}Id}`
- Body `data` includes `id: p.{resource}Id` alongside `type`

```ts
const response = await oroApiCall({
method: HttpMethod.PATCH,
resourceUri: `/{resources}/${p.{resource}Id}`,
auth: context.auth as OroAuth,
body: {
data: {
type: '{resources}',
id: p.{resource}Id,
attributes,
relationships,
},
},
headers: p.additionalHeaders as Record<string, string>,
});
```

---

## Step 6 — Wire up

**Three files to touch (always):**

### `src/lib/actions/index.ts`
```ts
export { create{Resource}Action } from './create-{resource}';
export { update{Resource}Action } from './update-{resource}';
```

### `src/index.ts`
Add to the `import` and to the `actions: [...]` array:
```ts
import { create{Resource}Action, update{Resource}Action } from './lib/actions';

// inside createPiece actions array:
create{Resource}Action,
update{Resource}Action,
```

### Bump `package.json` version
Increment patch version (e.g. `0.3.0` → `0.3.1`) — required so live flows pick up the change.

---

## Step 7 — Verify

```bash
npx turbo run lint --filter=@activepieces/piece-orocommerce
```

Must exit with `0 errors`. Fix any lint issues before finishing.

---

## Quick-look reference

### File locations

| File | Purpose |
|---|---|
| `src/lib/actions/create-{resource}.ts` | New create action |
| `src/lib/actions/update-{resource}.ts` | New update action |
| `src/lib/actions/index.ts` | Re-exports all actions |
| `src/lib/common/props.ts` | All shared dropdowns |
| `src/lib/common/client.ts` | `oroApiCall`, `fetchCollection` |
| `src/lib/common/jsonapi-body-utils.ts` | `pickDefined`, `buildRels`, `parseAdditional*` |
| `src/index.ts` | Piece registration |

### `buildRels` signatures recap

```ts
// Single relationship (data: { type, id })
relName: ['json-api-type', p.propValue]

// Single wrapped in array (data: [{ type, id }]) — many = true
relName: ['json-api-type', p.propValue, true]
```

Values that are `null`, `undefined`, or `''` are automatically skipped by `buildRels`.

### `oroApiCall` signature recap

```ts
await oroApiCall({
method: HttpMethod.POST | HttpMethod.PATCH | HttpMethod.GET | HttpMethod.DELETE,
resourceUri: '/collection' | '/collection/${id}',
auth: context.auth as OroAuth,
body?: Record<string, unknown>,
queryParams?: Record<string, string>,
headers?: Record<string, string>,
});
// returns { body: unknown, status: number }
```

---

## Critical reminders

1. **`name` is permanent** — once published, `name: 'create_xyz'` must never change; flows store it.
2. **Required rels on create** — hard-code them as `{ data: { type, id: p.x ?? '' } }` outside `buildRels`; `buildRels` skips empty strings which would silently omit a required rel.
3. **`additionalAttributes/Relations/Headers` always present** — add all three to every action for extensibility.
4. **`pickDefined` for optional attributes** — prevents sending `null`/`undefined` to the API on updates.
5. **Multi-value rels need `many: true`** — check the spec example: `"data": [...]` → `true`, `"data": {...}` → omit.
6. **Lint must pass** — unused imports are lint errors; import only the dropdowns the action actually uses.
7. **Bump `package.json` version** — patch bump for every change; without it live flows never get your fix.

Loading
Loading