Order Cancellation
Wordpress order cancellation working with Fluent Forms and WooCommerce
by Your Name · github.com/enfrte/order-cancellation · website
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/enfrte/order-cancellation/archive/refs/heads/master.zipReadme
Support for these software versions
Fluent forms version 6.2.5
Wordpress version 7.0
WooCommerce version 10.8.1
PHP 8.x
Do not use NodeJS, npm or Node based bundlers.
User Story: Order Cancellation Request Workflow
Overview
As an unregistered customer,
I want to submit a cancellation request for one or more orders,
so that I can request a refund or cancellation before the order is processed.
Functional Requirements
Cancellation Request Form
The cancellation request form shall contain:
- Customer email address (required)
- Order ID repeater field (minimum 1 order ID required)
- Submit button
The customer may add multiple order IDs using the repeater field.
Upon successful submission:
-
A cancellation request record shall be created.
-
The request status shall be set to:
Pending
-
A success message shall be displayed on the form page.
-
A confirmation email shall be sent to the customer.
-
A notification email shall be sent to administrators.
Status Definitions
The system shall support only the following statuses:
| Status | Meaning |
|---|---|
| Pending | Awaiting administrator review |
| Refunded | Refund approved or completed |
| Denied | Refund request denied |
| Request Cancelled | Customer withdrew the request |
No other status values shall be permitted.
The status should be set on the form entry, but not on the form the customer fills.
Customer Confirmation Email
The customer confirmation email shall include:
- Submitted order ID(s)
- Submission timestamp
- Current status (
Pending) - Unique cancellation request reference
- Secure cancellation request link
Secure Cancellation Link
The cancellation request link shall:
-
Contain a cryptographically secure random token
-
Not expose the Fluent Forms entry ID
-
Be valid for a configurable period (default 30 days)
-
Be usable only once
-
Become invalid after the request status changes to:
- Refunded
- Denied
- Request Cancelled
If the token is invalid, expired, or already used:
- The customer shall see an appropriate error message
- No status changes shall occur
Cancel Cancellation Request
When the customer clicks the cancellation request cancellation link:
-
The token shall be validated
-
The request status shall be updated to:
Request Cancelled
-
A confirmation message shall be displayed
-
The administrator shall receive a notification email
-
The customer shall receive a confirmation email
Duplicate Request Validation
When a customer submits a cancellation request:
The system shall validate the submitted order ID and customer email address.
A duplicate request exists when:
- Email address matches
- Order ID matches
- Existing request status is not
Request Cancelled
If one or more duplicate order IDs are found:
- Submission shall be rejected
- No new request shall be created
- The customer shall see a message identifying the duplicate order ID(s)
Example:
Existing request:
- customer@example.com
- Order 1001
- Order 1002
New request:
- customer@example.com
- Order 1002
- Order 1003
Result:
- Submission rejected
- Customer informed that Order 1002 already has an active cancellation request
Order Validation
Before creating a cancellation request:
The system shall verify:
- The order ID exists
- The supplied email address matches the order owner
If validation fails:
- Submission shall be rejected
- No request shall be created
- The customer shall receive an appropriate error message
Example:
"The order number and email address do not match our records."
Administrative Processing
Administrators shall be able to:
- View cancellation requests
- Filter requests by status
- Search by order ID
- Search by email address
- Update request status
- Add administrative notes
Administrative Notes
Administrators may enter notes when processing a request.
Examples:
- Refund processed manually
- Customer contacted support
- Reason for denial
Administrative notes shall:
- Be stored with the request history
- Be included in customer notifications where appropriate
Refunded Status
When an administrator changes status to Refunded:
- The status shall be saved
- Status change history shall be recorded
- The customer shall receive a notification email
The email shall include:
- Order ID(s)
- Updated status
- Administrative note (if provided)
Denied Status
When an administrator changes status to Denied:
- The status shall be saved
- Status change history shall be recorded
- The customer shall receive a notification email
The email shall include:
- Order ID(s)
- Updated status
- Reason for denial
- Administrative note (if provided)
Email Delivery Failure Handling
If email delivery fails:
- The cancellation request shall still be created or updated
- The failure shall be logged
- Administrators shall be able to review email delivery failures
Email delivery failures shall not prevent request processing.
Abuse Prevention
The system shall implement protection against abuse.
Requirements:
- CAPTCHA validation
- Rate limiting by IP address
- Rate limiting by email address
- Whitelist for email and IP addresses for testers and developers.
Default limits:
- Maximum 25 submissions per email address per hour
- Maximum 50 submissions per IP address per hour
Limits shall be configurable.
Audit Requirements
The system shall store:
- Request creation timestamp
- Last updated timestamp
- Status change timestamp
- Previous status
- New status
- Last admin performing the update
- Customer email address
- Order ID(s)
- Administrative notes
- Email delivery results
Audit history shall remain accessible to administrators.
Audit records shall not be editable.
Data Retention & Privacy
The system shall support configurable retention periods.
Default retention period:
- 24 months after final status
After expiration:
- Request data may be automatically deleted or anonymised
Administrators shall be able to manually remove requests where required by applicable privacy regulations.
Scenarios
Scenario 1 – Submit Cancellation Request
Given a customer enters a valid email address
And enters one or more valid order IDs
And the order IDs belong to the supplied email address
When the form is submitted
Then a cancellation request is created
And the status is set to Pending
And the customer sees a success message
And the customer receives a confirmation email
And the administrator receives a notification email
Scenario 2 – Duplicate Request
Given a cancellation request already exists
And the email address matches
And the order ID matches
And the request status is not Request Cancelled
When the customer submits the form
Then submission is rejected
And the customer sees an error message
And no new request is created
Scenario 3 – Invalid Order Ownership
Given a customer enters an order ID
And the email address does not match the order owner
When the form is submitted
Then submission is rejected
And an error message is displayed
And no request is created
Scenario 4 – Customer Cancels Request
Given a customer has a pending cancellation request
And possesses a valid cancellation token
When they click the cancellation link
Then the request status becomes Request Cancelled
And the administrator receives a notification email
And the customer receives a confirmation email
Scenario 5 – Expired Cancellation Token
Given a cancellation token has expired
When the customer clicks the cancellation link
Then no status change occurs
And the customer sees an error message
Scenario 6 – Administrator Approves Refund
Given a cancellation request is pending
When an administrator changes the status to Refunded
Then the status is updated
And the action is recorded in the audit history
And the customer receives a refund notification email
Scenario 7 – Administrator Denies Request
Given a cancellation request is pending
When an administrator changes the status to Denied
Then the status is updated
And the action is recorded in the audit history
And the customer receives a denial notification email
Scenario 8 – Email Delivery Failure
Given a cancellation request is submitted
And an email cannot be delivered
When request processing completes
Then the request remains created
And the email failure is logged
And administrators can review the failure
Scenario 9 – Rate Limit Exceeded
Given a customer exceeds the configured submission limit
When another request is submitted
Then the submission is rejected
And the customer sees a rate limit message
And no request is created
Implementation
For this set of requirements, treat Fluent Forms as the UI layer and build the business logic in a custom plugin.
Why not purely Fluent Forms?
Fluent Forms can handle:
- Form creation
- Repeater fields
- Email notifications
- Success messages
- Entry storage
- Custom entry fields
- Basic conditional logic
But our requirements go beyond typical form functionality:
- Duplicate validation against existing requests
- Checking order ownership against your order system
- Secure single-use cancellation tokens
- Expiring cancellation links
- Custom status workflow
- Status-change-triggered emails
- Audit trail
- Rate limiting
- Data retention rules
Trying to implement all of that using Fluent Forms hooks, snippets, and settings will eventually create a large collection of custom code anyway.
Recommended architecture
Fluent Forms
Use Fluent Forms only for:
- Email field
- Order ID repeater
- CAPTCHA
- Success message
- Entry creation
Custom plugin
Handle:
- Validation
- Duplicate checks
- Cancellation tokens
- Status management
- Admin workflow
- Audit logs
- Email triggers
- Scheduled cleanup
- Fluent Forms form seletor with form compatibility test.
Example:
Customer
↓
Fluent Form (Cancel order)
↓
Custom Plugin Hook
↓
Validation
↓
Store request
↓
Send emails
Exportability
If we build everything directly into Fluent Forms:
- Form can usually be exported/imported as JSON.
- Our PHP snippets, hooks, custom actions and email logic generally cannot.
- Migrating to another site becomes difficult.
If we use a plugin:
- Fluent Form JSON contains only the form structure.
- Plugin contains all business logic.
- Deployment becomes:
1. Install plugin
2. Import Fluent Form JSON
3. Configure settings
Much cleaner.
What we should build
Plugin structure:
order-cancellation/
├── order-cancellation.php
├── src/
│ ├── Validation.php
│ ├── CancellationToken.php
│ ├── StatusManager.php
│ ├── EmailManager.php
│ ├── AuditLogger.php
│ └── Admin.php
├── templates/
└── assets/
Hooks:
fluentform/before_insert_submission
fluentform/submission_inserted
fluentform/after_update_entry
The form remains editable by non-developers in Fluent Forms, while all business rules live in version-controlled PHP.