Updates, overview extended, club view implemented
This commit is contained in:
@@ -10,16 +10,44 @@ const CalendarEvent = sequelize.define('CalendarEvent', {
|
||||
references: { model: Club, key: 'id' },
|
||||
onDelete: 'CASCADE',
|
||||
},
|
||||
eventType: {
|
||||
type: DataTypes.STRING(32),
|
||||
allowNull: false,
|
||||
defaultValue: 'club_event',
|
||||
field: 'event_type',
|
||||
},
|
||||
status: {
|
||||
type: DataTypes.STRING(32),
|
||||
allowNull: false,
|
||||
defaultValue: 'planning',
|
||||
},
|
||||
title: { type: DataTypes.STRING(255), allowNull: false },
|
||||
description: { type: DataTypes.TEXT, allowNull: true },
|
||||
location: { type: DataTypes.STRING(255), allowNull: true },
|
||||
startDate: { type: DataTypes.DATEONLY, allowNull: false, field: 'start_date' },
|
||||
endDate: { type: DataTypes.DATEONLY, allowNull: false, field: 'end_date' },
|
||||
registrationDeadline: {
|
||||
type: DataTypes.DATEONLY,
|
||||
allowNull: true,
|
||||
field: 'registration_deadline',
|
||||
},
|
||||
organizerUserId: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
field: 'organizer_user_id',
|
||||
},
|
||||
category: { type: DataTypes.STRING(64), allowNull: true },
|
||||
notes: { type: DataTypes.TEXT, allowNull: true },
|
||||
}, {
|
||||
tableName: 'calendar_events',
|
||||
underscored: true,
|
||||
timestamps: true,
|
||||
indexes: [{ fields: ['club_id', 'start_date'] }],
|
||||
indexes: [
|
||||
{ fields: ['club_id', 'start_date'] },
|
||||
{ fields: ['club_id', 'event_type'] },
|
||||
{ fields: ['club_id', 'status'] },
|
||||
{ fields: ['club_id', 'registration_deadline'] },
|
||||
],
|
||||
});
|
||||
|
||||
export default CalendarEvent;
|
||||
|
||||
@@ -49,6 +49,12 @@ const Club = sequelize.define('Club', {
|
||||
field: 'member_data_quality_requirements',
|
||||
comment: 'Configures which member fields are required for data quality checks'
|
||||
},
|
||||
feeRules: {
|
||||
type: DataTypes.JSON,
|
||||
allowNull: true,
|
||||
field: 'fee_rules',
|
||||
comment: 'Manual contribution rules for common club member groups'
|
||||
},
|
||||
outgoingInvoicePrefix: {
|
||||
type: DataTypes.STRING(24),
|
||||
allowNull: false,
|
||||
|
||||
87
backend/models/ClubAccountTransaction.js
Normal file
87
backend/models/ClubAccountTransaction.js
Normal file
@@ -0,0 +1,87 @@
|
||||
import { DataTypes } from 'sequelize';
|
||||
import sequelize from '../database.js';
|
||||
|
||||
const ClubAccountTransaction = sequelize.define('ClubAccountTransaction', {
|
||||
id: {
|
||||
type: DataTypes.BIGINT,
|
||||
primaryKey: true,
|
||||
autoIncrement: true,
|
||||
allowNull: false,
|
||||
},
|
||||
clubId: {
|
||||
type: DataTypes.BIGINT,
|
||||
allowNull: false,
|
||||
field: 'club_id',
|
||||
},
|
||||
accountId: {
|
||||
type: DataTypes.BIGINT,
|
||||
allowNull: false,
|
||||
field: 'account_id',
|
||||
},
|
||||
invoiceId: {
|
||||
type: DataTypes.BIGINT,
|
||||
allowNull: true,
|
||||
field: 'invoice_id',
|
||||
},
|
||||
paymentClaimId: {
|
||||
type: DataTypes.BIGINT,
|
||||
allowNull: true,
|
||||
field: 'payment_claim_id',
|
||||
},
|
||||
direction: {
|
||||
type: DataTypes.ENUM('credit', 'debit'),
|
||||
allowNull: false,
|
||||
defaultValue: 'credit',
|
||||
},
|
||||
bookingType: {
|
||||
type: DataTypes.ENUM('manual', 'invoice', 'adjustment', 'payment_claim'),
|
||||
allowNull: false,
|
||||
defaultValue: 'manual',
|
||||
field: 'booking_type',
|
||||
},
|
||||
status: {
|
||||
type: DataTypes.ENUM('planned', 'booked', 'cancelled'),
|
||||
allowNull: false,
|
||||
defaultValue: 'booked',
|
||||
},
|
||||
bookingDate: {
|
||||
type: DataTypes.DATEONLY,
|
||||
allowNull: false,
|
||||
field: 'booking_date',
|
||||
},
|
||||
valueDate: {
|
||||
type: DataTypes.DATEONLY,
|
||||
allowNull: true,
|
||||
field: 'value_date',
|
||||
},
|
||||
amountCents: {
|
||||
type: DataTypes.BIGINT,
|
||||
allowNull: false,
|
||||
field: 'amount_cents',
|
||||
},
|
||||
currencyCode: {
|
||||
type: DataTypes.STRING(3),
|
||||
allowNull: false,
|
||||
defaultValue: 'EUR',
|
||||
field: 'currency_code',
|
||||
},
|
||||
reference: {
|
||||
type: DataTypes.STRING(255),
|
||||
allowNull: true,
|
||||
},
|
||||
notes: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
},
|
||||
createdByUserId: {
|
||||
type: DataTypes.BIGINT,
|
||||
allowNull: true,
|
||||
field: 'created_by_user_id',
|
||||
},
|
||||
}, {
|
||||
underscored: true,
|
||||
tableName: 'club_account_transactions',
|
||||
timestamps: true,
|
||||
});
|
||||
|
||||
export default ClubAccountTransaction;
|
||||
73
backend/models/ClubCommunicationDeliveryLog.js
Normal file
73
backend/models/ClubCommunicationDeliveryLog.js
Normal file
@@ -0,0 +1,73 @@
|
||||
import { DataTypes } from 'sequelize';
|
||||
import sequelize from '../database.js';
|
||||
|
||||
const ClubCommunicationDeliveryLog = sequelize.define('ClubCommunicationDeliveryLog', {
|
||||
id: {
|
||||
type: DataTypes.BIGINT,
|
||||
primaryKey: true,
|
||||
autoIncrement: true,
|
||||
allowNull: false,
|
||||
},
|
||||
clubId: {
|
||||
type: DataTypes.BIGINT,
|
||||
allowNull: false,
|
||||
field: 'club_id',
|
||||
},
|
||||
threadId: {
|
||||
type: DataTypes.BIGINT,
|
||||
allowNull: false,
|
||||
field: 'thread_id',
|
||||
},
|
||||
recipientId: {
|
||||
type: DataTypes.BIGINT,
|
||||
allowNull: true,
|
||||
field: 'recipient_id',
|
||||
},
|
||||
createdByUserId: {
|
||||
type: DataTypes.BIGINT,
|
||||
allowNull: true,
|
||||
field: 'created_by_user_id',
|
||||
},
|
||||
status: {
|
||||
type: DataTypes.ENUM('sent', 'failed', 'skipped'),
|
||||
allowNull: false,
|
||||
defaultValue: 'failed',
|
||||
},
|
||||
attemptNo: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
defaultValue: 1,
|
||||
field: 'attempt_no',
|
||||
},
|
||||
retryable: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: false,
|
||||
},
|
||||
errorCode: {
|
||||
type: DataTypes.STRING(64),
|
||||
allowNull: true,
|
||||
field: 'error_code',
|
||||
},
|
||||
errorMessage: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
field: 'error_message',
|
||||
},
|
||||
transportMessageId: {
|
||||
type: DataTypes.STRING(255),
|
||||
allowNull: true,
|
||||
field: 'transport_message_id',
|
||||
},
|
||||
transportResponse: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
field: 'transport_response',
|
||||
},
|
||||
}, {
|
||||
underscored: true,
|
||||
tableName: 'club_communication_delivery_logs',
|
||||
timestamps: true,
|
||||
});
|
||||
|
||||
export default ClubCommunicationDeliveryLog;
|
||||
47
backend/models/ClubCommunicationMessage.js
Normal file
47
backend/models/ClubCommunicationMessage.js
Normal file
@@ -0,0 +1,47 @@
|
||||
import { DataTypes } from 'sequelize';
|
||||
import sequelize from '../database.js';
|
||||
|
||||
const ClubCommunicationMessage = sequelize.define('ClubCommunicationMessage', {
|
||||
id: {
|
||||
type: DataTypes.BIGINT,
|
||||
primaryKey: true,
|
||||
autoIncrement: true,
|
||||
allowNull: false,
|
||||
},
|
||||
threadId: {
|
||||
type: DataTypes.BIGINT,
|
||||
allowNull: false,
|
||||
field: 'thread_id',
|
||||
},
|
||||
clubId: {
|
||||
type: DataTypes.BIGINT,
|
||||
allowNull: false,
|
||||
field: 'club_id',
|
||||
},
|
||||
messageType: {
|
||||
type: DataTypes.ENUM('message', 'note'),
|
||||
allowNull: false,
|
||||
defaultValue: 'message',
|
||||
field: 'message_type',
|
||||
},
|
||||
direction: {
|
||||
type: DataTypes.ENUM('outbound', 'internal', 'inbound'),
|
||||
allowNull: false,
|
||||
defaultValue: 'outbound',
|
||||
},
|
||||
body: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: false,
|
||||
},
|
||||
createdByUserId: {
|
||||
type: DataTypes.BIGINT,
|
||||
allowNull: true,
|
||||
field: 'created_by_user_id',
|
||||
},
|
||||
}, {
|
||||
underscored: true,
|
||||
tableName: 'club_communication_messages',
|
||||
timestamps: true,
|
||||
});
|
||||
|
||||
export default ClubCommunicationMessage;
|
||||
84
backend/models/ClubCommunicationRecipient.js
Normal file
84
backend/models/ClubCommunicationRecipient.js
Normal file
@@ -0,0 +1,84 @@
|
||||
import { DataTypes } from 'sequelize';
|
||||
import sequelize from '../database.js';
|
||||
|
||||
const ClubCommunicationRecipient = sequelize.define('ClubCommunicationRecipient', {
|
||||
id: {
|
||||
type: DataTypes.BIGINT,
|
||||
primaryKey: true,
|
||||
autoIncrement: true,
|
||||
allowNull: false,
|
||||
},
|
||||
threadId: {
|
||||
type: DataTypes.BIGINT,
|
||||
allowNull: false,
|
||||
field: 'thread_id',
|
||||
},
|
||||
clubId: {
|
||||
type: DataTypes.BIGINT,
|
||||
allowNull: false,
|
||||
field: 'club_id',
|
||||
},
|
||||
memberId: {
|
||||
type: DataTypes.BIGINT,
|
||||
allowNull: true,
|
||||
field: 'member_id',
|
||||
},
|
||||
recipientName: {
|
||||
type: DataTypes.STRING(255),
|
||||
allowNull: false,
|
||||
field: 'recipient_name',
|
||||
},
|
||||
emailSnapshot: {
|
||||
type: DataTypes.STRING(255),
|
||||
allowNull: true,
|
||||
field: 'email_snapshot',
|
||||
},
|
||||
deliveryStatus: {
|
||||
type: DataTypes.ENUM('pending', 'sent', 'failed', 'skipped'),
|
||||
allowNull: false,
|
||||
defaultValue: 'pending',
|
||||
field: 'delivery_status',
|
||||
},
|
||||
deliveredAt: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true,
|
||||
field: 'delivered_at',
|
||||
},
|
||||
lastAttemptAt: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true,
|
||||
field: 'last_attempt_at',
|
||||
},
|
||||
attemptCount: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
defaultValue: 0,
|
||||
field: 'attempt_count',
|
||||
},
|
||||
retryable: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: false,
|
||||
},
|
||||
errorCode: {
|
||||
type: DataTypes.STRING(64),
|
||||
allowNull: true,
|
||||
field: 'error_code',
|
||||
},
|
||||
transportMessageId: {
|
||||
type: DataTypes.STRING(255),
|
||||
allowNull: true,
|
||||
field: 'transport_message_id',
|
||||
},
|
||||
errorMessage: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
field: 'error_message',
|
||||
},
|
||||
}, {
|
||||
underscored: true,
|
||||
tableName: 'club_communication_recipients',
|
||||
timestamps: true,
|
||||
});
|
||||
|
||||
export default ClubCommunicationRecipient;
|
||||
58
backend/models/ClubCommunicationTemplate.js
Normal file
58
backend/models/ClubCommunicationTemplate.js
Normal file
@@ -0,0 +1,58 @@
|
||||
import { DataTypes } from 'sequelize';
|
||||
import sequelize from '../database.js';
|
||||
|
||||
const ClubCommunicationTemplate = sequelize.define('ClubCommunicationTemplate', {
|
||||
id: {
|
||||
type: DataTypes.BIGINT,
|
||||
primaryKey: true,
|
||||
autoIncrement: true,
|
||||
allowNull: false,
|
||||
},
|
||||
clubId: {
|
||||
type: DataTypes.BIGINT,
|
||||
allowNull: false,
|
||||
field: 'club_id',
|
||||
},
|
||||
name: {
|
||||
type: DataTypes.STRING(160),
|
||||
allowNull: false,
|
||||
},
|
||||
category: {
|
||||
type: DataTypes.STRING(64),
|
||||
allowNull: false,
|
||||
defaultValue: 'general',
|
||||
},
|
||||
subjectTemplate: {
|
||||
type: DataTypes.STRING(255),
|
||||
allowNull: true,
|
||||
field: 'subject_template',
|
||||
},
|
||||
bodyTemplate: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: false,
|
||||
field: 'body_template',
|
||||
},
|
||||
variablesHint: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
field: 'variables_hint',
|
||||
},
|
||||
isSystemTemplate: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: false,
|
||||
field: 'is_system_template',
|
||||
},
|
||||
sortOrder: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
defaultValue: 0,
|
||||
field: 'sort_order',
|
||||
},
|
||||
}, {
|
||||
underscored: true,
|
||||
tableName: 'club_communication_templates',
|
||||
timestamps: true,
|
||||
});
|
||||
|
||||
export default ClubCommunicationTemplate;
|
||||
67
backend/models/ClubCommunicationThread.js
Normal file
67
backend/models/ClubCommunicationThread.js
Normal file
@@ -0,0 +1,67 @@
|
||||
import { DataTypes } from 'sequelize';
|
||||
import sequelize from '../database.js';
|
||||
|
||||
const ClubCommunicationThread = sequelize.define('ClubCommunicationThread', {
|
||||
id: {
|
||||
type: DataTypes.BIGINT,
|
||||
primaryKey: true,
|
||||
autoIncrement: true,
|
||||
allowNull: false,
|
||||
},
|
||||
clubId: {
|
||||
type: DataTypes.BIGINT,
|
||||
allowNull: false,
|
||||
field: 'club_id',
|
||||
},
|
||||
threadType: {
|
||||
type: DataTypes.ENUM('direct', 'group', 'broadcast'),
|
||||
allowNull: false,
|
||||
defaultValue: 'direct',
|
||||
field: 'thread_type',
|
||||
},
|
||||
subject: {
|
||||
type: DataTypes.STRING(255),
|
||||
allowNull: false,
|
||||
},
|
||||
status: {
|
||||
type: DataTypes.ENUM('draft', 'scheduled', 'sent', 'archived'),
|
||||
allowNull: false,
|
||||
defaultValue: 'draft',
|
||||
},
|
||||
createdByUserId: {
|
||||
type: DataTypes.BIGINT,
|
||||
allowNull: true,
|
||||
field: 'created_by_user_id',
|
||||
},
|
||||
distributionGroupId: {
|
||||
type: DataTypes.BIGINT,
|
||||
allowNull: true,
|
||||
field: 'distribution_group_id',
|
||||
},
|
||||
recipientMemberId: {
|
||||
type: DataTypes.BIGINT,
|
||||
allowNull: true,
|
||||
field: 'recipient_member_id',
|
||||
},
|
||||
scheduledAt: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true,
|
||||
field: 'scheduled_at',
|
||||
},
|
||||
recipientFilters: {
|
||||
type: DataTypes.JSON,
|
||||
allowNull: true,
|
||||
field: 'recipient_filters',
|
||||
},
|
||||
sentAt: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true,
|
||||
field: 'sent_at',
|
||||
},
|
||||
}, {
|
||||
underscored: true,
|
||||
tableName: 'club_communication_threads',
|
||||
timestamps: true,
|
||||
});
|
||||
|
||||
export default ClubCommunicationThread;
|
||||
47
backend/models/ClubDistributionGroup.js
Normal file
47
backend/models/ClubDistributionGroup.js
Normal file
@@ -0,0 +1,47 @@
|
||||
import { DataTypes } from 'sequelize';
|
||||
import sequelize from '../database.js';
|
||||
|
||||
const ClubDistributionGroup = sequelize.define('ClubDistributionGroup', {
|
||||
id: {
|
||||
type: DataTypes.BIGINT,
|
||||
primaryKey: true,
|
||||
autoIncrement: true,
|
||||
allowNull: false,
|
||||
},
|
||||
clubId: {
|
||||
type: DataTypes.BIGINT,
|
||||
allowNull: false,
|
||||
field: 'club_id',
|
||||
},
|
||||
name: {
|
||||
type: DataTypes.STRING(255),
|
||||
allowNull: false,
|
||||
},
|
||||
description: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
},
|
||||
groupType: {
|
||||
type: DataTypes.ENUM('manual', 'training_group', 'team', 'custom'),
|
||||
allowNull: false,
|
||||
defaultValue: 'manual',
|
||||
field: 'group_type',
|
||||
},
|
||||
isSystemGroup: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: false,
|
||||
field: 'is_system_group',
|
||||
},
|
||||
filterDefinition: {
|
||||
type: DataTypes.JSON,
|
||||
allowNull: true,
|
||||
field: 'filter_definition',
|
||||
},
|
||||
}, {
|
||||
underscored: true,
|
||||
tableName: 'club_distribution_groups',
|
||||
timestamps: true,
|
||||
});
|
||||
|
||||
export default ClubDistributionGroup;
|
||||
33
backend/models/ClubDistributionGroupMember.js
Normal file
33
backend/models/ClubDistributionGroupMember.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import { DataTypes } from 'sequelize';
|
||||
import sequelize from '../database.js';
|
||||
|
||||
const ClubDistributionGroupMember = sequelize.define('ClubDistributionGroupMember', {
|
||||
id: {
|
||||
type: DataTypes.BIGINT,
|
||||
primaryKey: true,
|
||||
autoIncrement: true,
|
||||
allowNull: false,
|
||||
},
|
||||
groupId: {
|
||||
type: DataTypes.BIGINT,
|
||||
allowNull: false,
|
||||
field: 'group_id',
|
||||
},
|
||||
memberId: {
|
||||
type: DataTypes.BIGINT,
|
||||
allowNull: false,
|
||||
field: 'member_id',
|
||||
},
|
||||
}, {
|
||||
underscored: true,
|
||||
tableName: 'club_distribution_group_members',
|
||||
timestamps: true,
|
||||
indexes: [
|
||||
{
|
||||
unique: true,
|
||||
fields: ['group_id', 'member_id'],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
export default ClubDistributionGroupMember;
|
||||
61
backend/models/ClubDocument.js
Normal file
61
backend/models/ClubDocument.js
Normal file
@@ -0,0 +1,61 @@
|
||||
import { DataTypes } from 'sequelize';
|
||||
import sequelize from '../database.js';
|
||||
|
||||
const ClubDocument = sequelize.define('ClubDocument', {
|
||||
clubId: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
field: 'club_id',
|
||||
},
|
||||
documentType: {
|
||||
type: DataTypes.STRING(32),
|
||||
allowNull: false,
|
||||
field: 'document_type',
|
||||
},
|
||||
title: {
|
||||
type: DataTypes.STRING(255),
|
||||
allowNull: false,
|
||||
},
|
||||
description: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
},
|
||||
status: {
|
||||
type: DataTypes.STRING(32),
|
||||
allowNull: false,
|
||||
defaultValue: 'active',
|
||||
},
|
||||
visibilityScope: {
|
||||
type: DataTypes.STRING(32),
|
||||
allowNull: false,
|
||||
defaultValue: 'board',
|
||||
field: 'visibility_scope',
|
||||
},
|
||||
ownerUserId: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
field: 'owner_user_id',
|
||||
},
|
||||
currentVersionNo: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
defaultValue: 1,
|
||||
field: 'current_version_no',
|
||||
},
|
||||
archivedAt: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true,
|
||||
field: 'archived_at',
|
||||
},
|
||||
}, {
|
||||
tableName: 'club_documents',
|
||||
underscored: true,
|
||||
timestamps: true,
|
||||
indexes: [
|
||||
{ fields: ['club_id', 'document_type', 'status'] },
|
||||
{ fields: ['club_id', 'visibility_scope'] },
|
||||
{ fields: ['club_id', 'current_version_no'] },
|
||||
],
|
||||
});
|
||||
|
||||
export default ClubDocument;
|
||||
35
backend/models/ClubDocumentLink.js
Normal file
35
backend/models/ClubDocumentLink.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import { DataTypes } from 'sequelize';
|
||||
import sequelize from '../database.js';
|
||||
|
||||
const ClubDocumentLink = sequelize.define('ClubDocumentLink', {
|
||||
documentId: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
field: 'document_id',
|
||||
},
|
||||
linkedEntityType: {
|
||||
type: DataTypes.STRING(32),
|
||||
allowNull: false,
|
||||
field: 'linked_entity_type',
|
||||
},
|
||||
linkedEntityId: {
|
||||
type: DataTypes.BIGINT,
|
||||
allowNull: false,
|
||||
field: 'linked_entity_id',
|
||||
},
|
||||
createdAt: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false,
|
||||
defaultValue: DataTypes.NOW,
|
||||
field: 'created_at',
|
||||
},
|
||||
}, {
|
||||
tableName: 'club_document_links',
|
||||
underscored: true,
|
||||
timestamps: false,
|
||||
indexes: [
|
||||
{ fields: ['linked_entity_type', 'linked_entity_id'] },
|
||||
],
|
||||
});
|
||||
|
||||
export default ClubDocumentLink;
|
||||
65
backend/models/ClubDocumentVersion.js
Normal file
65
backend/models/ClubDocumentVersion.js
Normal file
@@ -0,0 +1,65 @@
|
||||
import { DataTypes } from 'sequelize';
|
||||
import sequelize from '../database.js';
|
||||
|
||||
const ClubDocumentVersion = sequelize.define('ClubDocumentVersion', {
|
||||
documentId: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
field: 'document_id',
|
||||
},
|
||||
versionNo: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
field: 'version_no',
|
||||
},
|
||||
fileName: {
|
||||
type: DataTypes.STRING(255),
|
||||
allowNull: false,
|
||||
field: 'file_name',
|
||||
},
|
||||
storagePath: {
|
||||
type: DataTypes.STRING(500),
|
||||
allowNull: false,
|
||||
field: 'storage_path',
|
||||
},
|
||||
mimeType: {
|
||||
type: DataTypes.STRING(120),
|
||||
allowNull: true,
|
||||
field: 'mime_type',
|
||||
},
|
||||
fileSizeBytes: {
|
||||
type: DataTypes.BIGINT,
|
||||
allowNull: true,
|
||||
field: 'file_size_bytes',
|
||||
},
|
||||
checksumSha256: {
|
||||
type: DataTypes.STRING(64),
|
||||
allowNull: true,
|
||||
field: 'checksum_sha256',
|
||||
},
|
||||
uploadedByUserId: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
field: 'uploaded_by_user_id',
|
||||
},
|
||||
uploadedAt: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false,
|
||||
defaultValue: DataTypes.NOW,
|
||||
field: 'uploaded_at',
|
||||
},
|
||||
changeNote: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
field: 'change_note',
|
||||
},
|
||||
}, {
|
||||
tableName: 'club_document_versions',
|
||||
underscored: true,
|
||||
timestamps: false,
|
||||
indexes: [
|
||||
{ unique: true, fields: ['document_id', 'version_no'] },
|
||||
],
|
||||
});
|
||||
|
||||
export default ClubDocumentVersion;
|
||||
@@ -13,10 +13,30 @@ const ClubInvoiceParty = sequelize.define('ClubInvoiceParty', {
|
||||
defaultValue: 'customer',
|
||||
field: 'party_type',
|
||||
},
|
||||
status: {
|
||||
type: DataTypes.STRING(32),
|
||||
allowNull: false,
|
||||
defaultValue: 'active',
|
||||
},
|
||||
name: {
|
||||
type: DataTypes.STRING(255),
|
||||
allowNull: false,
|
||||
},
|
||||
contractReference: {
|
||||
type: DataTypes.STRING(120),
|
||||
allowNull: true,
|
||||
field: 'contract_reference',
|
||||
},
|
||||
validFrom: {
|
||||
type: DataTypes.DATEONLY,
|
||||
allowNull: true,
|
||||
field: 'valid_from',
|
||||
},
|
||||
validTo: {
|
||||
type: DataTypes.DATEONLY,
|
||||
allowNull: true,
|
||||
field: 'valid_to',
|
||||
},
|
||||
contactName: {
|
||||
type: DataTypes.STRING(255),
|
||||
allowNull: true,
|
||||
@@ -70,6 +90,12 @@ const ClubInvoiceParty = sequelize.define('ClubInvoiceParty', {
|
||||
tableName: 'club_invoice_parties',
|
||||
underscored: true,
|
||||
timestamps: true,
|
||||
indexes: [
|
||||
{ fields: ['club_id', 'party_type'] },
|
||||
{ fields: ['club_id', 'status'] },
|
||||
{ fields: ['club_id', 'valid_from'] },
|
||||
{ fields: ['club_id', 'valid_to'] },
|
||||
],
|
||||
});
|
||||
|
||||
export default ClubInvoiceParty;
|
||||
|
||||
@@ -38,6 +38,12 @@ const ClubPaymentClaim = sequelize.define('ClubPaymentClaim', {
|
||||
allowNull: false,
|
||||
field: 'amount_cents'
|
||||
},
|
||||
paidAmountCents: {
|
||||
type: DataTypes.BIGINT,
|
||||
allowNull: false,
|
||||
defaultValue: 0,
|
||||
field: 'paid_amount_cents'
|
||||
},
|
||||
currencyCode: {
|
||||
type: DataTypes.STRING(3),
|
||||
allowNull: false,
|
||||
@@ -64,6 +70,11 @@ const ClubPaymentClaim = sequelize.define('ClubPaymentClaim', {
|
||||
allowNull: true,
|
||||
field: 'settled_at'
|
||||
},
|
||||
lastPaidAt: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true,
|
||||
field: 'last_paid_at'
|
||||
},
|
||||
archivedAt: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true,
|
||||
|
||||
@@ -123,6 +123,60 @@ const Member = sequelize.define('Member', {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
},
|
||||
membershipStatus: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
defaultValue: 'active',
|
||||
field: 'membership_status',
|
||||
},
|
||||
membershipType: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
defaultValue: 'regular',
|
||||
field: 'membership_type',
|
||||
},
|
||||
joinedOn: {
|
||||
type: DataTypes.DATEONLY,
|
||||
allowNull: true,
|
||||
field: 'joined_on',
|
||||
},
|
||||
leftOn: {
|
||||
type: DataTypes.DATEONLY,
|
||||
allowNull: true,
|
||||
field: 'left_on',
|
||||
},
|
||||
contributionGroupCode: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: true,
|
||||
field: 'contribution_group_code',
|
||||
},
|
||||
needsSepaMandate: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: false,
|
||||
field: 'needs_sepa_mandate',
|
||||
},
|
||||
sepaMandateReference: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: true,
|
||||
field: 'sepa_mandate_reference',
|
||||
},
|
||||
isArchived: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: false,
|
||||
field: 'is_archived',
|
||||
},
|
||||
archivedAt: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true,
|
||||
field: 'archived_at',
|
||||
},
|
||||
archivedReason: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
field: 'archived_reason',
|
||||
},
|
||||
active: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
|
||||
@@ -57,6 +57,9 @@ import BillingRun from './BillingRun.js';
|
||||
import BillingDocument from './BillingDocument.js';
|
||||
import BillingDocumentValue from './BillingDocumentValue.js';
|
||||
import BillingUserSetting from './BillingUserSetting.js';
|
||||
import ClubDocument from './ClubDocument.js';
|
||||
import ClubDocumentVersion from './ClubDocumentVersion.js';
|
||||
import ClubDocumentLink from './ClubDocumentLink.js';
|
||||
import FriendlyMatch from './FriendlyMatch.js';
|
||||
import FriendlyMatchShared from './FriendlyMatchShared.js';
|
||||
import FriendlyMatchInvitation from './FriendlyMatchInvitation.js';
|
||||
@@ -75,6 +78,7 @@ import ClubRequestNote from './ClubRequestNote.js';
|
||||
import ClubSepaMandate from './ClubSepaMandate.js';
|
||||
import ClubPaymentClaim from './ClubPaymentClaim.js';
|
||||
import ClubAccount from './ClubAccount.js';
|
||||
import ClubAccountTransaction from './ClubAccountTransaction.js';
|
||||
import ClubInvoiceParty from './ClubInvoiceParty.js';
|
||||
import ClubInvoice from './ClubInvoice.js';
|
||||
import ClubInvoiceItem from './ClubInvoiceItem.js';
|
||||
@@ -82,6 +86,13 @@ import ClubTask from './ClubTask.js';
|
||||
import ClubTaskSuppression from './ClubTaskSuppression.js';
|
||||
import ClubRole from './ClubRole.js';
|
||||
import ClubUserRole from './ClubUserRole.js';
|
||||
import ClubCommunicationThread from './ClubCommunicationThread.js';
|
||||
import ClubCommunicationMessage from './ClubCommunicationMessage.js';
|
||||
import ClubCommunicationRecipient from './ClubCommunicationRecipient.js';
|
||||
import ClubCommunicationDeliveryLog from './ClubCommunicationDeliveryLog.js';
|
||||
import ClubCommunicationTemplate from './ClubCommunicationTemplate.js';
|
||||
import ClubDistributionGroup from './ClubDistributionGroup.js';
|
||||
import ClubDistributionGroupMember from './ClubDistributionGroupMember.js';
|
||||
// Official tournaments relations
|
||||
OfficialTournament.hasMany(OfficialCompetition, { foreignKey: 'tournamentId', as: 'competitions' });
|
||||
OfficialCompetition.belongsTo(OfficialTournament, { foreignKey: 'tournamentId', as: 'tournament' });
|
||||
@@ -193,6 +204,13 @@ ClubTeamMember.belongsTo(Member, { foreignKey: 'memberId', as: 'member' });
|
||||
ClubTeam.hasMany(TeamDocument, { foreignKey: 'clubTeamId', as: 'documents' });
|
||||
TeamDocument.belongsTo(ClubTeam, { foreignKey: 'clubTeamId', as: 'clubTeam' });
|
||||
|
||||
Club.hasMany(ClubDocument, { foreignKey: 'clubId', as: 'documents' });
|
||||
ClubDocument.belongsTo(Club, { foreignKey: 'clubId', as: 'club' });
|
||||
ClubDocument.hasMany(ClubDocumentVersion, { foreignKey: 'documentId', as: 'versions' });
|
||||
ClubDocumentVersion.belongsTo(ClubDocument, { foreignKey: 'documentId', as: 'document' });
|
||||
ClubDocument.hasMany(ClubDocumentLink, { foreignKey: 'documentId', as: 'links' });
|
||||
ClubDocumentLink.belongsTo(ClubDocument, { foreignKey: 'documentId', as: 'document' });
|
||||
|
||||
Match.belongsTo(Location, { foreignKey: 'locationId', as: 'location' });
|
||||
Location.hasMany(Match, { foreignKey: 'locationId', as: 'matches' });
|
||||
|
||||
@@ -483,9 +501,15 @@ Club.hasMany(ClubPaymentClaim, { foreignKey: 'clubId', as: 'paymentClaims' });
|
||||
ClubPaymentClaim.belongsTo(Club, { foreignKey: 'clubId', as: 'club' });
|
||||
Member.hasMany(ClubPaymentClaim, { foreignKey: 'memberId', as: 'paymentClaims' });
|
||||
ClubPaymentClaim.belongsTo(Member, { foreignKey: 'memberId', as: 'member', constraints: false });
|
||||
ClubPaymentClaim.hasMany(ClubAccountTransaction, { foreignKey: 'paymentClaimId', as: 'transactions' });
|
||||
ClubAccountTransaction.belongsTo(ClubPaymentClaim, { foreignKey: 'paymentClaimId', as: 'paymentClaim', constraints: false });
|
||||
|
||||
Club.hasMany(ClubAccount, { foreignKey: 'clubId', as: 'accounts' });
|
||||
ClubAccount.belongsTo(Club, { foreignKey: 'clubId', as: 'club' });
|
||||
Club.hasMany(ClubAccountTransaction, { foreignKey: 'clubId', as: 'accountTransactions' });
|
||||
ClubAccountTransaction.belongsTo(Club, { foreignKey: 'clubId', as: 'club' });
|
||||
ClubAccount.hasMany(ClubAccountTransaction, { foreignKey: 'accountId', as: 'transactions' });
|
||||
ClubAccountTransaction.belongsTo(ClubAccount, { foreignKey: 'accountId', as: 'account' });
|
||||
|
||||
Club.hasMany(ClubInvoiceParty, { foreignKey: 'clubId', as: 'invoiceParties' });
|
||||
ClubInvoiceParty.belongsTo(Club, { foreignKey: 'clubId', as: 'club' });
|
||||
@@ -498,6 +522,10 @@ ClubInvoice.belongsTo(ClubAccount, { foreignKey: 'accountId', as: 'account', con
|
||||
ClubAccount.hasMany(ClubInvoice, { foreignKey: 'accountId', as: 'invoices' });
|
||||
User.hasMany(ClubInvoice, { foreignKey: 'createdByUserId', as: 'createdInvoices' });
|
||||
ClubInvoice.belongsTo(User, { foreignKey: 'createdByUserId', as: 'createdByUser', constraints: false });
|
||||
ClubInvoice.hasMany(ClubAccountTransaction, { foreignKey: 'invoiceId', as: 'transactions' });
|
||||
ClubAccountTransaction.belongsTo(ClubInvoice, { foreignKey: 'invoiceId', as: 'invoice', constraints: false });
|
||||
User.hasMany(ClubAccountTransaction, { foreignKey: 'createdByUserId', as: 'createdAccountTransactions' });
|
||||
ClubAccountTransaction.belongsTo(User, { foreignKey: 'createdByUserId', as: 'createdByUser', constraints: false });
|
||||
|
||||
ClubInvoice.hasMany(ClubInvoiceItem, { foreignKey: 'invoiceId', as: 'items' });
|
||||
ClubInvoiceItem.belongsTo(ClubInvoice, { foreignKey: 'invoiceId', as: 'invoice' });
|
||||
@@ -522,6 +550,45 @@ ClubUserRole.belongsTo(Club, { foreignKey: 'clubId', as: 'club', constraints: fa
|
||||
User.hasMany(ClubUserRole, { foreignKey: 'userId', as: 'clubRoleAssignments' });
|
||||
ClubUserRole.belongsTo(User, { foreignKey: 'userId', as: 'user', constraints: false });
|
||||
|
||||
Club.hasMany(ClubCommunicationThread, { foreignKey: 'clubId', as: 'communicationThreads' });
|
||||
ClubCommunicationThread.belongsTo(Club, { foreignKey: 'clubId', as: 'club' });
|
||||
User.hasMany(ClubCommunicationThread, { foreignKey: 'createdByUserId', as: 'createdCommunicationThreads' });
|
||||
ClubCommunicationThread.belongsTo(User, { foreignKey: 'createdByUserId', as: 'createdByUser', constraints: false });
|
||||
ClubCommunicationThread.belongsTo(ClubDistributionGroup, { foreignKey: 'distributionGroupId', as: 'distributionGroup', constraints: false });
|
||||
ClubDistributionGroup.hasMany(ClubCommunicationThread, { foreignKey: 'distributionGroupId', as: 'threads' });
|
||||
ClubCommunicationThread.belongsTo(Member, { foreignKey: 'recipientMemberId', as: 'recipientMember', constraints: false });
|
||||
Member.hasMany(ClubCommunicationThread, { foreignKey: 'recipientMemberId', as: 'communicationThreads' });
|
||||
|
||||
Club.hasMany(ClubCommunicationMessage, { foreignKey: 'clubId', as: 'communicationMessages' });
|
||||
ClubCommunicationMessage.belongsTo(Club, { foreignKey: 'clubId', as: 'club' });
|
||||
ClubCommunicationThread.hasMany(ClubCommunicationMessage, { foreignKey: 'threadId', as: 'messages' });
|
||||
ClubCommunicationMessage.belongsTo(ClubCommunicationThread, { foreignKey: 'threadId', as: 'thread' });
|
||||
User.hasMany(ClubCommunicationMessage, { foreignKey: 'createdByUserId', as: 'createdCommunicationMessages' });
|
||||
ClubCommunicationMessage.belongsTo(User, { foreignKey: 'createdByUserId', as: 'createdByUser', constraints: false });
|
||||
Club.hasMany(ClubCommunicationTemplate, { foreignKey: 'clubId', as: 'communicationTemplates' });
|
||||
ClubCommunicationTemplate.belongsTo(Club, { foreignKey: 'clubId', as: 'club' });
|
||||
Club.hasMany(ClubCommunicationRecipient, { foreignKey: 'clubId', as: 'communicationRecipients' });
|
||||
ClubCommunicationRecipient.belongsTo(Club, { foreignKey: 'clubId', as: 'club' });
|
||||
ClubCommunicationThread.hasMany(ClubCommunicationRecipient, { foreignKey: 'threadId', as: 'recipients' });
|
||||
ClubCommunicationRecipient.belongsTo(ClubCommunicationThread, { foreignKey: 'threadId', as: 'thread' });
|
||||
Member.hasMany(ClubCommunicationRecipient, { foreignKey: 'memberId', as: 'communicationRecipientEntries' });
|
||||
ClubCommunicationRecipient.belongsTo(Member, { foreignKey: 'memberId', as: 'member', constraints: false });
|
||||
Club.hasMany(ClubCommunicationDeliveryLog, { foreignKey: 'clubId', as: 'communicationDeliveryLogs' });
|
||||
ClubCommunicationDeliveryLog.belongsTo(Club, { foreignKey: 'clubId', as: 'club' });
|
||||
ClubCommunicationThread.hasMany(ClubCommunicationDeliveryLog, { foreignKey: 'threadId', as: 'deliveryLogs' });
|
||||
ClubCommunicationDeliveryLog.belongsTo(ClubCommunicationThread, { foreignKey: 'threadId', as: 'thread' });
|
||||
ClubCommunicationRecipient.hasMany(ClubCommunicationDeliveryLog, { foreignKey: 'recipientId', as: 'deliveryLogs' });
|
||||
ClubCommunicationDeliveryLog.belongsTo(ClubCommunicationRecipient, { foreignKey: 'recipientId', as: 'recipient', constraints: false });
|
||||
User.hasMany(ClubCommunicationDeliveryLog, { foreignKey: 'createdByUserId', as: 'createdCommunicationDeliveryLogs' });
|
||||
ClubCommunicationDeliveryLog.belongsTo(User, { foreignKey: 'createdByUserId', as: 'createdByUser', constraints: false });
|
||||
|
||||
Club.hasMany(ClubDistributionGroup, { foreignKey: 'clubId', as: 'distributionGroups' });
|
||||
ClubDistributionGroup.belongsTo(Club, { foreignKey: 'clubId', as: 'club' });
|
||||
ClubDistributionGroup.hasMany(ClubDistributionGroupMember, { foreignKey: 'groupId', as: 'memberships' });
|
||||
ClubDistributionGroupMember.belongsTo(ClubDistributionGroup, { foreignKey: 'groupId', as: 'group' });
|
||||
Member.hasMany(ClubDistributionGroupMember, { foreignKey: 'memberId', as: 'distributionGroupMemberships' });
|
||||
ClubDistributionGroupMember.belongsTo(Member, { foreignKey: 'memberId', as: 'member', constraints: false });
|
||||
|
||||
export {
|
||||
User,
|
||||
Log,
|
||||
@@ -548,6 +615,8 @@ export {
|
||||
ClubTeam,
|
||||
ClubTeamMember,
|
||||
TeamDocument,
|
||||
Season,
|
||||
Location,
|
||||
Group,
|
||||
GroupActivity,
|
||||
Tournament,
|
||||
@@ -558,6 +627,8 @@ export {
|
||||
TournamentResult,
|
||||
ExternalTournamentParticipant,
|
||||
TournamentPairing,
|
||||
TournamentStage,
|
||||
TournamentStageAdvancement,
|
||||
Accident,
|
||||
UserToken,
|
||||
OfficialTournament,
|
||||
@@ -579,6 +650,9 @@ export {
|
||||
BillingDocument,
|
||||
BillingDocumentValue,
|
||||
BillingUserSetting,
|
||||
ClubDocument,
|
||||
ClubDocumentVersion,
|
||||
ClubDocumentLink,
|
||||
FriendlyMatch,
|
||||
FriendlyMatchShared,
|
||||
FriendlyMatchInvitation,
|
||||
@@ -597,6 +671,7 @@ export {
|
||||
ClubSepaMandate,
|
||||
ClubPaymentClaim,
|
||||
ClubAccount,
|
||||
ClubAccountTransaction,
|
||||
ClubInvoiceParty,
|
||||
ClubInvoice,
|
||||
ClubInvoiceItem,
|
||||
@@ -604,4 +679,11 @@ export {
|
||||
ClubTaskSuppression,
|
||||
ClubRole,
|
||||
ClubUserRole,
|
||||
ClubCommunicationThread,
|
||||
ClubCommunicationMessage,
|
||||
ClubCommunicationRecipient,
|
||||
ClubCommunicationDeliveryLog,
|
||||
ClubCommunicationTemplate,
|
||||
ClubDistributionGroup,
|
||||
ClubDistributionGroupMember,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user