Prepare the project for production deployment and final client
acceptance testing. Adds preflight fail-fast command, hardened FX rate
importer, currency seeder, deploy scripts, E2E smoke test, and the
43-item UAT checklist document with sign-off form.
Key changes:
- Phase 3.9.1 — hotfix (AddressBookEntry):
- Add $attributes defaults (use_count=0, is_default=false) so
instance values are populated right after create() without
refresh(). Resolves the red test
`it_increments_use_count_and_sets_last_used_at`.
- Phase 3.10 — deploy infrastructure (Laravel):
- Add `ifnex:preflight` command: fail-fast audit of production
environment (APP_ENV, APP_DEBUG, APP_KEY, IFNEX_API_KEY,
IFNEX_BRIDGE_API_KEY, ZARINPAL_SANDBOX, DB_CONNECTION, CORS,
currencies seeded, PHP extensions, storage writable). Exits 1
if any check fails; supports --skip-db for pre-migrate runs.
- Add `ifnex:import-fx-rates` command: replacement for
`ifnex:update-rates`. Fetches USD/AED from Exir.io + EUR/CNY
from FreeCurrencyAPI. Supports --auto-approve (cron use) and
--threshold (max change % for auto-approve). Logs critical on
HTTP failure. URL configurable via EXIR_API_URL env.
- Add `CurrencySeeder`: creates 5 base currencies (USD/AED/EUR/
CNY/IRR) with rate=0 (IRR=1). Idempotent — does not overwrite
real rates already set by admin or cron.
- Update `DatabaseSeeder`: skip super_admin with password
'password' in production (still created in local/testing).
- Fix `bootstrap/app.php`: remove dead `use ApiKeyAuth` import
(actual class is ApiKeyMiddleware). Latent fatal if api_key
alias was used.
- Add `config/ifnex.php` exir block + preflight config.
- Harden `.env.example`: MySQL default, EXIR_API_URL,
SANCTUM_STATEFUL_DOMAINS, APP_TIMEZONE, LOG_DAILY_DAYS, fix
duplicate CURRENCY_API_KEY.
- Phase 3.10 — deploy scripts (Linux):
- Add `scripts/deploy.sh`: idempotent 13-step deploy (composer
install → key:generate → preflight → migrate → seed → FX import
→ cache → chown). Fail-fast with set -e.
- Add `scripts/cron-exir-rates.sh`: daily cron wrapper for
`ifnex:import-fx-rates --source=all --auto-approve`.
- Phase 3.10.1 — preflight hotfix:
- Make expected DB connection configurable
(ifnex.preflight.expected_db_connection) instead of hardcoded
'mysql'. Prevents cascade test failure when tests would have to
mutate database.default to mysql in a sqlite test environment
(Unknown database ':memory:' → broken connection pool → 22
previously-green tests fail with "There is already an active
transaction").
- Rewrite IfnexPreflightTest to use config() rather than mutating
database.default.
- Phase 3.11 — UAT:
- Add `ifnex:smoke-test` command: E2E post-deploy automated test
(25+ checks: DB connection, core tables, currencies with
non-zero rates, countries count, roles, admin user, system
settings, storage writable, config/route cache, 4 API
endpoints: /up, /countries, /track/{invalid}, /customer/profile
without token).
- Add 9 feature tests for smoke-test (PASS + 6 FAIL + custom URL
+ 422/500 handling + auth bypass detection).
- Add `UAT-3.11.md`: 43-item Persian checklist for client
acceptance testing across 15 feature areas. Includes sign-off
form for both parties (client + VernaSoft).
- Update `CLIENT_DELIVERY.md` to record phases 3.10 and 3.11.
Tests:
- Total: 51 → 82 tests, 150 → 220+ assertions, all green.
- New: IfnexPreflightTest (9), IfnexImportFxRatesTest (9),
CurrencySeederTest (4), IfnexSmokeTestTest (9) = 31 new tests.
Documentation:
- DEPLOYMENT_HANDOFF.md §2.4: add CurrencySeeder + import-fx-rates.
- DEPLOYMENT_HANDOFF.md §2.8: update cron to use cron-exir-rates.sh.
- UAT-3.11.md: new 43-item client acceptance checklist + sign-off.
- CLIENT_DELIVERY.md: record phases 3.10 and 3.11 completion.
6 lines
2.5 KiB
JavaScript
6 lines
2.5 KiB
JavaScript
/*! This file is auto-generated */
|
|
(function() {
|
|
"use strict";var wp;(wp||={}).blockSerializationDefaultParser=(()=>{var m=Object.defineProperty;var S=Object.getOwnPropertyDescriptor;var T=Object.getOwnPropertyNames;var B=Object.prototype.hasOwnProperty;var F=(t,n)=>{for(var s in n)m(t,s,{get:n[s],enumerable:!0})},H=(t,n,s,o)=>{if(n&&typeof n=="object"||typeof n=="function")for(let e of T(n))!B.call(t,e)&&e!==s&&m(t,e,{get:()=>n[e],enumerable:!(o=S(n,e))||o.enumerable});return t};var w=t=>H(m({},"__esModule",{value:!0}),t);var L={};F(L,{parse:()=>y});var a,l,i,f,C=/<!--[ \t\f\r\n]+(\/)?wp:([a-z][a-z0-9_-]*\/)?([a-z][a-z0-9_-]*)[ \t\f\r\n]+({(?:(?=([^}]+|}+(?=})|(?!}[ \t\f\r\n]+\/?-->)[^])*)\5|[^]*?)}[ \t\f\r\n]+)?(\/)?-->/g;function k(t,n,s,o,e){return{blockName:t,attrs:n,innerBlocks:s,innerHTML:o,innerContent:e}}function g(t){return k(null,{},[],t,[t])}function N(t,n,s,o,e){return{block:t,tokenStart:n,tokenLength:s,prevOffset:o||n+s,leadingHtmlStart:e}}var y=t=>{a=t,l=0,i=[],f=[],C.lastIndex=0;do;while(A());return i};function A(){let t=f.length,n=J(),[s,o,e,r,c]=n,p=r>l?l:null;switch(s){case"no-more-tokens":if(t===0)return d(),!1;if(t===1)return v(),!1;for(;0<f.length;)v();return!1;case"void-block":return t===0?(p!==null&&i.push(g(a.substr(p,r-p))),i.push(k(o,e,[],"",[])),l=r+c,!0):(z(k(o,e,[],"",[]),r,c),l=r+c,!0);case"block-opener":return f.push(N(k(o,e,[],"",[]),r,c,r+c,p)),l=r+c,!0;case"block-closer":if(t===0)return d(),!1;if(t===1)return v(r),l=r+c,!0;let u=f.pop(),h=a.substr(u.prevOffset,r-u.prevOffset);return u.block.innerHTML+=h,u.block.innerContent.push(h),u.prevOffset=r+c,z(u.block,u.tokenStart,u.tokenLength,r+c),l=r+c,!0;default:return d(),!1}}function I(t){try{return JSON.parse(t)}catch{return null}}function J(){let t=C.exec(a);if(t===null)return["no-more-tokens","",null,0,0];let n=t.index,[s,o,e,r,c,,p]=t,u=s.length,h=!!o,O=!!p,b=(e||"core/")+r,M=!!c,x=M?I(c):{};return O?["void-block",b,x,n,u]:h?["block-closer",b,null,n,u]:["block-opener",b,x,n,u]}function d(t){let n=t||a.length-l;n!==0&&i.push(g(a.substr(l,n)))}function z(t,n,s,o){let e=f[f.length-1];e.block.innerBlocks.push(t);let r=a.substr(e.prevOffset,n-e.prevOffset);r&&(e.block.innerHTML+=r,e.block.innerContent.push(r)),e.block.innerContent.push(null),e.prevOffset=o||n+s}function v(t){let{block:n,leadingHtmlStart:s,prevOffset:o,tokenStart:e}=f.pop(),r=t?a.substr(o,t-o):a.substr(o);r&&(n.innerHTML+=r,n.innerContent.push(r)),s!==null&&i.push(g(a.substr(s,e-s))),i.push(n)}return w(L);})();
|
|
(window.wp ||= {}).blockSerializationDefaultParser = wp.blockSerializationDefaultParser;
|
|
})();
|