Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(EMS-3633): data migration - declarations #2819

Merged
merged 6 commits into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 1 addition & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@

## [2.18.0](https://github.com/UK-Export-Finance/exip/compare/v2.17.0...v2.18.0) (2024-07-25)


### Features

* **EMS-3631:** declaration versions - database restructure, application creation ([#2805](https://github.com/UK-Export-Finance/exip/issues/2805)) ([2353b5f](https://github.com/UK-Export-Finance/exip/commit/2353b5f853ecb0c827662d7bd960dbd18a37eb62))
- **EMS-3631:** declaration versions - database restructure, application creation ([#2805](https://github.com/UK-Export-Finance/exip/issues/2805)) ([2353b5f](https://github.com/UK-Export-Finance/exip/commit/2353b5f853ecb0c827662d7bd960dbd18a37eb62))

## [2.17.0](https://github.com/UK-Export-Finance/exip/compare/v2.16.0...v2.17.0) (2024-07-25)

Expand Down
10 changes: 5 additions & 5 deletions database/exip.sql
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# Version 2
#
# Database: exip
# Generation Time: 2024-07-24 14:03:29 +0000
# Generation Time: 2024-07-25 15:31:00 +0000
# ************************************************************

CREATE DATABASE IF NOT EXISTS `exip`;
Expand Down Expand Up @@ -589,13 +589,13 @@ DROP TABLE IF EXISTS `Declaration`;

CREATE TABLE `Declaration` (
`id` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`agreeToConfidentiality` tinyint(1) DEFAULT NULL,
`agreeHowDataWillBeUsed` tinyint(1) DEFAULT NULL,
`agreeToAntiBribery` tinyint(1) DEFAULT NULL,
`agreeToConfidentiality` tinyint(1) DEFAULT NULL,
`agreeToConfirmationAndAcknowledgements` tinyint(1) DEFAULT NULL,
`willExportWithAntiBriberyCodeOfConduct` tinyint(1) DEFAULT NULL,
`hasAntiBriberyCodeOfConduct` tinyint(1) DEFAULT NULL,
`agreeHowDataWillBeUsed` tinyint(1) DEFAULT NULL,
`application` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`hasAntiBriberyCodeOfConduct` tinyint(1) DEFAULT NULL,
`willExportWithAntiBriberyCodeOfConduct` tinyint(1) DEFAULT NULL,
`version` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `Declaration_application_idx` (`application`),
Expand Down
11 changes: 6 additions & 5 deletions src/api/.keystone/config.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/api/constants/declarations/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ describe('api/constants/declarations', () => {
it('should return an object', () => {
const expected = {
VERSIONS: DECLARATION_VERSIONS,
V1_DECLARATIONS: DECLARATION_VERSIONS[0],
LATEST_DECLARATIONS: DECLARATION_VERSIONS[DECLARATION_VERSIONS.length - 1],
};

Expand Down
1 change: 1 addition & 0 deletions src/api/constants/declarations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import DECLARATION_VERSIONS from './versions';
*/
export const DECLARATIONS = {
VERSIONS: DECLARATION_VERSIONS,
V1_DECLARATIONS: DECLARATION_VERSIONS[0],
LATEST_DECLARATIONS: DECLARATION_VERSIONS[DECLARATION_VERSIONS.length - 1],
};

Expand Down
13 changes: 11 additions & 2 deletions src/api/data-migration/version-1-to-version-2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ This directory contains source code for migrating version 1 of EXIP data into th
- `Buyer` table - 3x new relationships - `buyerTradingHistory`, `contact`, `relationship`.
- `Company` table - 1x new relationship - `differentTradingAddress`.
- `Company` table - 1x new field - `differentTradingName`.
- `Declaration` table - 2x new fields - `version`, `exportContract`.
- `Declaration` table - 3x removed fields - `antiBribery`, `confirmationAndAcknowledgements`, `howDataWillBeUsed.
- `DeclarationAntiBribery` table - removed.
- `DeclarationConfidentiality` table - removed.
- `DeclarationConfirmationAndAcknowledgement` table - removed.
- `DeclarationHowDataWillBeUsed` table - removed.
- `Eligibility` table - 1x new field - `hasEndBuyer`.
- `ExportContract` table - 2x new relationships - `agent`, `privateMarket`.
- `ExportContract` table - 1x new field - `paymentTermsDescription`.
Expand All @@ -29,6 +35,7 @@ This directory contains source code for migrating version 1 of EXIP data into th
- BuyerRelationship
- BuyerTradingHistory
- CompanyDifferentTradingAddress
- DeclarationVersion
- ExportContractAgent
- ExportContractAgentService
- ExportContractAgentServiceCharge
Expand Down Expand Up @@ -74,8 +81,10 @@ The migration should successfully do the following:
6. Create new account status relationships.
7. Remove old account status fields.
8. Update buyers.
9. Create new application relationships.
10. Exit the process.
9. Remove old declaration fields.
10. Remove old declaration content tables.
11. Create new application relationships.
12. Exit the process.

## How to ensure that data migration was successful

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Connection } from 'mysql2/promise';
import getAllDeclarations from '../get-all-declarations';
import getAllDeclarationVersions from '../get-all-declaration-versions';
import executeSqlQuery from '../execute-sql-query';

/**
* updateDeclarationVersionField
* Update "version" columns in "declaration" entries
* 1) Map over each "declaration".
* 2) Generate "version" values (version ID relationship)
* 3) Update the values in the Declaration table.
* @param {Connection} connection: SQL database connection
* @returns {Promise<Array<ApplicationPrivateMarket>>} Updated declarations
*/
const updateDeclarationVersionField = async (connection: Connection) => {
const loggingMessage = 'Creating declarationVersion entries with declaration relationships';

console.info(`✅ ${loggingMessage}`);

try {
const declarations = await getAllDeclarations(connection);
const declarationVersions = await getAllDeclarationVersions(connection);

const declarationPromises = declarations.map(async (declaration: object, index: number) => {
const version = declarationVersions[index];

const query = `
UPDATE Declaration SET version='${version.id}' WHERE id='${declaration.id}'
`;

const updated = await executeSqlQuery({
connection,
query,
loggingMessage: `Updating version column in declartion table for declaration ${declaration.id}`,
});

return updated;
});

return Promise.all(declarationPromises);
} catch (err) {
console.error(`🚨 error ${loggingMessage} %O`, err);

throw new Error(`🚨 error ${loggingMessage} ${err}`);
}
};

export default updateDeclarationVersionField;
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Connection } from 'mysql2/promise';
import submittedApplications from './submitted-applications';
import nonSubmittedApplications from './non-submitted-applications';

/**
* createDeclarationVersionRelationship
* Create new "declaration version" entires with version numbers and "declaration" relationships.
* @param {Connection} connection: SQL database connection
* @returns {Promise<Array<DeclarationVersion>>} Declaration version entries
*/
const createDeclarationVersionRelationship = async (connection: Connection) => {
const loggingMessage = 'Creating declarationVersion entries with declaration relationships for non-submitted applications';

console.info(`✅ ${loggingMessage}`);

try {
const promises = Promise.all([await submittedApplications(connection), await nonSubmittedApplications(connection)]);

return promises;
} catch (err) {
console.error(`🚨 error ${loggingMessage} %O`, err);

throw new Error(`🚨 error ${loggingMessage} ${err}`);
}
};

export default createDeclarationVersionRelationship;
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { Connection } from 'mysql2/promise';
import { DECLARATIONS } from '../../../../constants';
import getAllNonSubmittedApplications from '../../get-all-non-submitted-applications';
import createCuid from '../../create-cuid';
import executeSqlQuery from '../../execute-sql-query';
import { Application } from '../../../../types';

const {
ANTI_BRIBERY,
ANTI_BRIBERY_CODE_OF_CONDUCT,
ANTI_BRIBERY_EXPORTING_WITH_CODE_OF_CONDUCT,
CONFIDENTIALITY,
CONFIRMATION_AND_ACKNOWLEDGEMENTS,
} = DECLARATIONS.LATEST_DECLARATIONS;

/**
* createDeclarationVersionRelationship
* Create new "declaration version" entires with version numbers and "declaration" relationships,
* for applications that do NOT have a SUBMITTED status.
* Applications that have NOT been submitted, prior to V2, should have the latest declaration versions.
* 1) Map over each application
* 2) Create new database values with a CUID and version numbers
* 3) Add entries to the DeclarationVersion table
* @param {Connection} connection: SQL database connection
* @returns {Promise<Array<DeclarationVersion>>} Declaration version entries
*/
const createDeclarationVersionRelationshipNotSubmittedApplications = async (connection: Connection) => {
const loggingMessage = 'Creating declarationVersion entries with declaration relationships for non-submitted applications';

console.info(`✅ ${loggingMessage}`);

const nonSubmittedApplications = await getAllNonSubmittedApplications(connection);

if (!nonSubmittedApplications.length) {
console.info('ℹ️ No non-submitted applications available - no need to create declarationVersion entries');

return false;
}

try {
const declarationPromises = nonSubmittedApplications.map(async (application: Application) => {
const { declaration: declarationId } = application;

const idValues = `'${createCuid()}', '${declarationId}',`;

const versionValues = `'${ANTI_BRIBERY}', '${CONFIDENTIALITY}', '${CONFIRMATION_AND_ACKNOWLEDGEMENTS}', '${ANTI_BRIBERY_CODE_OF_CONDUCT}', '${ANTI_BRIBERY_EXPORTING_WITH_CODE_OF_CONDUCT}'`;

const theValues = `(${idValues} ${versionValues})`;

const query = await executeSqlQuery({
connection,
query: `INSERT INTO DeclarationVersion (id, declaration, agreeToAntiBribery, agreeToConfidentiality, agreeToConfirmationAndAcknowledgements, hasAntiBriberyCodeOfConduct, willExportWithAntiBriberyCodeOfConduct) VALUES ${theValues}`,
loggingMessage: `Creating DeclarationVersion entry for application ${application.id}`,
});

return query;
});

return Promise.all(declarationPromises);
} catch (err) {
console.error(`🚨 error ${loggingMessage} %O`, err);

throw new Error(`🚨 error ${loggingMessage} ${err}`);
}
};

export default createDeclarationVersionRelationshipNotSubmittedApplications;
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { Connection } from 'mysql2/promise';
import { DECLARATIONS } from '../../../../constants';
import getAllSubmittedApplications from '../../get-all-submitted-applications';
import createCuid from '../../create-cuid';
import executeSqlQuery from '../../execute-sql-query';
import { Application } from '../../../../types';

const {
ANTI_BRIBERY,
ANTI_BRIBERY_CODE_OF_CONDUCT,
ANTI_BRIBERY_EXPORTING_WITH_CODE_OF_CONDUCT,
CONFIDENTIALITY,
CONFIRMATION_AND_ACKNOWLEDGEMENTS,
HOW_YOUR_DATA_WILL_BE_USED,
} = DECLARATIONS.V1_DECLARATIONS;

/**
* createDeclarationVersionRelationshipSubmittedApplications
* Create new "declaration version" entires with version numbers and "declaration" relationships,
* for applications with a SUBMITTED status.
* Applications that have already been submitted, prior to V2, should have V1 declaration versions.
* 1) Map over each application
* 2) Create new database values with a CUID and version numbers
* 3) Add entries to the DeclarationVersion table
* @param {Connection} connection: SQL database connection
* @returns {Promise<Array<DeclarationVersion>>} Declaration version entries
*/
const createDeclarationVersionRelationshipSubmittedApplications = async (connection: Connection) => {
const loggingMessage = 'Creating declarationVersion entries with declaration relationships for submitted applications';

console.info(`✅ ${loggingMessage}`);

const submittedApplications = await getAllSubmittedApplications(connection);

if (!submittedApplications.length) {
console.info('ℹ️ No submitted applications available - no need to create declarationVersion entries');

return false;
}

try {
const declarationPromises = submittedApplications.map(async (application: Application) => {
const { declaration: declarationId } = application;

const idValues = `'${createCuid()}', '${declarationId}',`;

const versionValues = `'${HOW_YOUR_DATA_WILL_BE_USED}', '${ANTI_BRIBERY}', '${CONFIDENTIALITY}', '${CONFIRMATION_AND_ACKNOWLEDGEMENTS}', '${ANTI_BRIBERY_CODE_OF_CONDUCT}', '${ANTI_BRIBERY_EXPORTING_WITH_CODE_OF_CONDUCT}'`;

const theValues = `(${idValues} ${versionValues})`;

const query = await executeSqlQuery({
connection,
query: `INSERT INTO DeclarationVersion (id, declaration, agreeHowDataWillBeUsed, agreeToAntiBribery, agreeToConfidentiality, agreeToConfirmationAndAcknowledgements, hasAntiBriberyCodeOfConduct, willExportWithAntiBriberyCodeOfConduct) VALUES ${theValues}`,
loggingMessage: `Creating DeclarationVersion entry for application ${application.id}`,
});

return query;
});

return Promise.all(declarationPromises);
} catch (err) {
console.error(`🚨 error ${loggingMessage} %O`, err);

throw new Error(`🚨 error ${loggingMessage} ${err}`);
}
};

export default createDeclarationVersionRelationshipSubmittedApplications;
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ import { Connection } from 'mysql2/promise';
import getAllApplications from '../get-all-applications';
import createLossPayee from './loss-payee';
import createJointlyInsuredParty from './jointly-insured-party';
import updateLossPayeeFinancialUkVector from './loss-payee/update-loss-payee-financial-uk-vector';
import updateLossPayeeFinancialInternationalVector from './loss-payee/update-loss-payee-financial-international-vector';
import createExportContractAgent from './export-contract-agent';
import createPrivateMarket from './private-market';
import updateExportContractPrivateMarket from './export-contract-private-market';
import createCompanyDifferentTradingAddress from './create-company-different-trading-address';
import updateCompanyDifferentTradingAddress from './update-company-different-trading-address';
import createDeclarationVersionRelationship from './declaration-version-relationship';
import updateDeclarationVersionField from './declaration-version-field';
import updateLossPayeeFinancialUkVector from './loss-payee/update-loss-payee-financial-uk-vector';
import updateLossPayeeFinancialInternationalVector from './loss-payee/update-loss-payee-financial-international-vector';

/**
* createNewApplicationRelationships
Expand All @@ -34,6 +36,8 @@ const createNewApplicationRelationships = async (connection: Connection) => {
updateExportContractPrivateMarket(connection),
createCompanyDifferentTradingAddress(connection, applications),
updateCompanyDifferentTradingAddress(connection),
createDeclarationVersionRelationship(connection, applications),
updateDeclarationVersionField(connection, applications),
]);

await updateLossPayeeFinancialUkVector(connection);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Connection } from 'mysql2/promise';
import executeSqlQuery from '../execute-sql-query';

/**
* createDeclarationVersionTable
* Create new "declaration version" database table.
* @param {Connection} connection: SQL database connection
* @returns {Promise<Array<object>>} executeSqlQuery response
*/
const createDeclarationVersionTable = (connection: Connection) => {
const loggingMessage = 'Creating TABLE - declaration version';

const query = `
CREATE TABLE DeclarationVersion (
id varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
agreeHowDataWillBeUsed varchar(3) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
agreeToAntiBribery varchar(3) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
agreeToConfidentiality varchar(3) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
agreeToConfirmationAndAcknowledgements varchar(3) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
hasAntiBriberyCodeOfConduct varchar(3) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
willExportWithAntiBriberyCodeOfConduct varchar(3) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
declaration varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
PRIMARY KEY (id),
KEY DeclarationVersion_declaration_idx (declaration),
CONSTRAINT DeclarationVersion_declaration_fkey FOREIGN KEY (declaration) REFERENCES Declaration (id) ON DELETE
SET
NULL ON UPDATE CASCADE
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
`;

return executeSqlQuery({ connection, query, loggingMessage });
};

export default createDeclarationVersionTable;
Loading
Loading