Limits and guarantees¶
Gift Cards adds an expiry date, a balance page and a liability figure to OpenCart's own gift vouchers. This page sets out what that does and does not include, so you know before you buy.
At a glance¶
| If you are asking | The short answer |
|---|---|
| Will changing the period move the dates on cards already sold? | No, in either direction. A card's date is written once and the period is never read again. More |
| Does the gift card email tell the recipient when the card expires? | Yes, when the card has a date that has not passed, in both the order-completion email and the one Send sends. Three cases leave it out silently. More |
| Can editing an order restore a spent card? | Yes, on OpenCart 4.0.x. That is core's own order edit, and Gift Cards does not fix it. More |
| Does it run on OpenCart 4.1? | No. OpenCart removed gift vouchers in 4.1.0.0, and Gift Cards refuses to install there. More |
| Is expiry enforced while the module is switched off, or after it is removed? | Switched off, yes: cards are still dated and expired cards are still refused, and only the screens a shopper sees go. Removed, no. More |
| Does an expired card lose its balance? | No. It stops being spendable; the balance is still shown and still counted as owed. More |
| Will it stop me setting a period below a legal minimum? | No. It warns, and saves what you typed. More |
| Are cards issued by hand, or sold before I set a period, given a date? | A card you add by hand gets a date from your period filled in on the Add form, which you can change or clear. Cards sold before you set a period stay undated. More |
| Does a refund void the cards the order sold? | No. You get the figures on the order screen, and the decision is yours. More |
| Can an integration read a card's code through the API? | No, under no name and by no filter. It reads each card's balance, expiry date and liability figure, and only once you switch the API on. More |
| Does uninstalling delete the expiry dates? | No. All three of its tables stay. More |
What it guarantees¶
- A card's expiry date is that card's own. It is generated once, from the store-wide period, on the day the card's order first reaches a completed status, and then written down. Nothing reads the period again.
- Changing the period never moves a card that already has a date, in either direction, and there is no button that does it. This follows from where the date is stored rather than from a rule somebody has to remember.
- Expiry only ever subtracts. Any unreadable or missing date means "no expiry", so the card resolves exactly as OpenCart would have resolved it. A bad row in this extension's table can never stop a valid code working.
- A card works through the whole of its expiry day. A card dated 31 March is spendable until the last second of 31 March, in your store's own timezone.
- Your cards stay OpenCart's. Gift Cards never writes to
oc_voucher: no row, no column, not the status flag. Remove the extension and every card you have sold is exactly where it was and still redeems. - One balance, worked out one way. The holder's page, the order panel and the liability report all read the same figure through the same code, so they cannot disagree with each other.
- The balance page tells nobody anything they did not already know. Every refusal is the same sentence, and it is challenged on the address the card was sent to, never the buyer's.
- The expiry date travels in OpenCart's own gift card email. Both the email sent when the order that sold the card completes and the one the Send button (the envelope) on a card's form in Sales → Gift Vouchers sends end their redeem line with "This gift card can be used until the end of" the card's date. A card with no date, or one already past its date, gets no sentence, so a card you resend after it expired is not told to use it by a day that has gone. There is no setting that leaves the date out. It is silently absent, and the email goes exactly as OpenCart made it, in three cases:
- a theme whose own gift card email template does not print OpenCart's redeem line;
- a language pack whose redeem sentence does not carry the code exactly once;
- a code that two cards share, because the email names the card only by its code.
- Nothing is deleted when you remove it. See what an uninstall keeps.
The two things that will surprise you¶
Editing a completed order can quietly restore a spent card¶
On OpenCart 4.0.x, editing an order that sold a gift card can put that card back to its full face value, with nothing said and nothing logged.
This is OpenCart's own behaviour and it happens with no extensions installed at all. When you edit an existing order, OpenCart's order API deletes the order's voucher rows and creates them again from scratch, with new identifiers. The redemption history still points at the old ones. So the card comes back as a new, unspent card of the same face value, and whatever had been spent off it is attached to an identifier nothing reads any more.
Gift Cards does not fix this and does not claim to. It is core's order rebuild, several layers below anything an extension can reach, and an extension that tried to stitch the histories back together would be guessing at which card was which. What it does mean for you:
- The card's expiry date is lost with the old identifier too. The new card has no row in this extension's table, so it has no expiry.
- The liability report will count the restored face value as owed, because it is.
What to do instead: avoid editing orders that sold gift cards. If you must, check the card afterwards in Sales → Gift Vouchers and correct the amount and the expiry date by hand. The order screen's Gift Cards panel shows what it looks like now.
This does not happen on OpenCart 4.1.0.3, but 4.1 has no gift vouchers at all, so upgrading is not a workaround.
A card that expires between the basket and the Confirm button flags the order¶
If a card is still valid when the shopper applies it and has expired by the time they press Confirm, OpenCart marks that order with your configured fraud status instead of accepting the card. The order is not lost, and no money is taken twice. It lands in the order status you nominated under System → Settings → Option → Checkout → Fraud Order Status, waiting for you to look at it.
This is OpenCart's own behaviour and Gift Cards does not work around it. When OpenCart confirms an order it re-reads every voucher code on it. A code it cannot resolve at that moment is treated as an attempt to confirm an order with a discount that is not real, which looks the same as fraud and is handled the same way.
It is very hard to hit. The shopper is told the card is not valid at the apply-code box and again on every recalculation of the cart and the checkout, so reaching Confirm with a just-expired card means the card expired inside the confirm step: in practice, midnight passed between pressing the button and the order being written.
What to do when you see one: open the order, look at the Gift Cards panel and at Sales → Gift Vouchers for the card's expiry date. If the card expired minutes earlier and you want to honour it, extend the date and put the order back to a normal status. Nothing has been charged or refunded in the meantime.
Gift Cards will not silently accept an expired card at confirmation to avoid this, because the checkout would then apply a discount your own expiry rule says is over.
What it does not do¶
It does not run on OpenCart 4.1 or above¶
OpenCart deleted the gift voucher feature in 4.1.0.0. The model, the tables and the checkout box are all absent, not renamed or deprecated. There is nothing there for this extension to add a date to, so it refuses to install rather than creating two empty tables and offering three screens with nothing to say. The full reasoning includes what it probes for.
Switching it off keeps expiry; removing it lifts it¶
Status switches off what a shopper and your voucher form see. It does not switch off expiry, because expiry is your money and your legal floor rather than a screen. With the module switched off:
- Cards whose orders complete are still dated, from the validity period you set. The date is read once, when the order first completes, so a card sold while the switch was off would otherwise never expire.
- An expired card is still refused at the checkout, exactly as it is with the module on.
- The Expires on field disappears from OpenCart's voucher form, and a date posted to that form anyway is not saved.
- The buyer's notice, the footer link, the balance page and the order panel all go too. The liability report stays, because it reads rows the store already has.
An update brings the module back switched off, the way a fresh install does, and expiry carries on through that window. Switch it back on to bring the shopper's screens back. What an update keeps lists everything else that comes back at its shipped value.
Removing the extension lifts expiry for good, because its listeners go with it: an expired card redeems again, exactly as OpenCart would redeem it with no extension installed, and new cards get no date. The dates already written stay in its own table.
It does not take the balance when a card expires¶
An expired card stops being spendable at checkout. That is all that happens. The money is still shown on the balance page, still counted in what you owe, and still yours to honour if you decide to. Whether an expired balance is forfeit depends on the law where you trade and on what you told the buyer, and this extension will not decide it for you by quietly zeroing something.
It does not enforce a legal minimum¶
Several countries set a minimum validity period for a gift card, and in Ireland selling below it is a criminal offence. Gift Cards shows you those floors and warns when you type a period below the highest of them, and then saves exactly what you typed.
It warns rather than refuses because there is no EU-wide rule to enforce: the floor is national, it ranges from no statute at all to five years, and this extension does not know which country you are selling into. Of the jurisdictions surveyed, six could be verified against a primary source and six could not, and the table says which. A country missing from that table is not a country with no rule; it is a country nobody checked. None of it is legal advice. See the legal floor on a gift card's expiry.
It suggests a date for a card you issue by hand, and never sets one¶
A voucher you create yourself in Sales → Gift Vouchers has no purchasing order behind it, so there is no moment at which the validity period could be read for it. Instead, when a period is set, the Add form fills the expiry date in from today plus that period and says so underneath. You can change it or clear it. Whatever is in the box when you press Save is the card's date, and an empty box is a card that never expires. Editing an existing card never fills the date in, and a voucher created by anything other than that form gets no date at all.
The same is true of every card sold before you installed Gift Cards, or before you set a period. There was no moment at which the period could have been read, and inventing one afterwards would be exactly the retroactive change the design rules out.
The one way such a card is dated later is by its own order: if an undated card's purchasing order is given a completed status again while a period is set, the card is dated from that day, the same as a card sold today.
It does not act on a refund¶
Refunding an order that sold gift cards voids nothing, claws nothing back and changes no balance. What you get is the Gift Cards panel on the order screen, showing each card, its face value, what has gone and what is left.
OpenCart already does the part that needs no judgement: a card whose purchasing order leaves a completed status stops resolving on its own, with no extension involved. The rest is a money question with two people in it. Somebody who was given the card has already spent part of it, and whether you or they absorb that is a decision this extension cannot take for you.
The balance page does not follow that rule. It shows what is on the card, so a card whose purchasing order is not at a completed status (still in flight, or refunded, cancelled or reopened since) shows its full remaining balance, and does not expire if it has no date, while OpenCart's checkout refuses it. A holder who asks why their card was turned down at the till is holding a card from an order that is not complete: check that order's status first.
The liability figure has no date filter and no per-store split¶
What your store owes on unspent gift cards is one number, as at right now, for the whole installation. There is no as-at date and no breakdown by storefront.
A date box would raise the question of which figure is meant, and two merchants comparing two of them would be comparing answers to different questions.
The list of cards under the figure does filter: by code or recipient, by which figure a card is counted in, and by cards expiring within a number of days. Its Download CSV button exports what the filters show, every page of it. The figures above the list never move with the filters, and the CSV carries no card code and no recipient name, because a code is all anybody needs to spend a card. Every amount is summed in your store's base currency, which is the currency OpenCart stores a voucher's face value in, so a multi-currency store gets one accurate total rather than a mixture.
The balance page will not tell anyone why it said no¶
A code it does not recognise, a live card with the wrong address, a card you switched off, and too many attempts from one place all produce the same sentence. There is no setting that makes it more specific, because a refusal that told them apart would let somebody with no card at all work out which codes exist, one guess at a time.
For the same reason the number of attempts allowed is fixed and not a setting. It is counted two ways at once (per address, and per card), and either limit can trip. The address is the one your web server sees, the same one OpenCart's own checks use: on a store behind a CDN or a reverse proxy that does not pass the visitor's address through, every holder can arrive from the proxy's address and share one allowance. The numbers and the window are published on settings.
The balance page cannot be put behind a login, and will not take the buyer's address¶
Both are deliberate. A recipient with no account is the person the page exists for, and an address the buyer chose is one the buyer could use to watch the recipient spend their present. If you do not want the page, switch it off; there is no third setting between those two.
Its settings are one set for the whole installation¶
They are not per storefront. A voucher is one global row in OpenCart, so a card sold through your second storefront is the same card, and a validity period that differed per storefront would be a promise the underlying table cannot keep.
The buyer's notice, the footer link and the order panel can be lost to a theme¶
The validity notice is placed by finding the gift card purchase form, the balance page's footer link by finding OpenCart's own Gift Certificates link, and the order panel by finding a known part of the order screen. A theme that rewrote any of the three loses that block. The page still renders and everything about the card itself is unaffected, but the buyer is not told, the link is not offered and the panel is not there.
The Expires on field on OpenCart's voucher form is placed the same way, above the form's Status row. An admin theme that rewrote that form loses the field, and with it the only way to type a card's date.
The API, and what it can read¶
Off until you switch it on, under API on the settings screen, and while it is
off every route answers as though this extension had no API at all. One read
resource: card is one of OpenCart's own gift vouchers, with what is left on it,
the date it expires, whether that date has passed and which liability figure it
is counted in. The API is generated from what the extension
actually answers.
- It only ever reads. Nothing can issue a card, change a balance or set an expiry date through it. An expiry date written by an integration would be the one door through which a card somebody paid for could be shortened.
- No card code is readable, by any name. A code is the money: whoever holds it spends the balance. It is not a field, not a filter and not a sort key, so an integration cannot look a card up by its code either. Nor are the sender, the recipient or the message readable; those are OpenCart's own data about two people, and an accounting system reconciling what you owe does not need them.
- The liability figure is not a separate answer. Every input to it is a field
on
card, so a walk of the cards grouped byfigureis the report. A second answer could only disagree with the first. - There is no "changed since" filter, and none can be honest. OpenCart's voucher row has no modified stamp, a redemption writes a history row and touches nothing on the card, and expired and the figure move with the clock and with an order's status. Walking the whole collection is the synchronisation, and it is resumable from wherever it stopped.
- Editing an order re-issues its cards under new ids. That is OpenCart's own behaviour (see above), and through the API it reads as cards gone and new full-value cards arrived. A full walk is the authoritative list; reconcile by absence.
- Each page reads OpenCart's whole voucher history table once. That table has no index on the card, and Gift Cards adds nothing to OpenCart's voucher tables, not even an index. It is the cost the liability report already pays once for the whole store, and it grows with the number of redemptions rather than cards.
- The credential is OpenCart's own API user, and it is not scoped. One is enough to read every extension's API on the store and core's own order API besides. Restrict it by IP address under System → Users → API, and treat it the way you would treat an admin login.
- Nothing records that anybody read anything. No read log, no per-credential audit trail, no rate limiting.
What an uninstall keeps¶
Removing Gift Cards deletes none of its data, and there is no button that does. All three of its tables stay: the one holding every expiry date, the balance page's record of recent attempts, and its own copy of your settings. What stops is the enforcing: with the extension gone, nothing refuses an expired card (see switching it off keeps expiry; removing it lifts it).
This is deliberate. In OpenCart an update is an uninstall followed by an install, so a clean-up on the way out would erase every expiry date on the store at every version bump. With them gone, you would quietly be back to issuing cards that never expire, and find out months later.
Your settings do come back across an update, with the exceptions listed on the changelog. OpenCart deletes them at the uninstall step and Gift Cards keeps its own copy to put back.
Your cards themselves are untouched by all of this, because they were never this extension's to begin with.
If you are evaluating Gift Cards against a requirement you do not find on this page or on the overview, assume it is not there and ask rather than inferring it.