Compare commits

...

4 Commits

Author SHA1 Message Date
standardci
68744379a6 chore(release): publish new version
- @standardnotes/analytics@2.7.2
2022-11-09 12:11:11 +00:00
Karol Sójko
90aef905af fix(analytics): mrr column types 2022-11-09 13:09:14 +01:00
standardci
c7cbc8966e chore(release): publish new version
- @standardnotes/analytics@2.7.1
2022-11-09 11:43:39 +00:00
Karol Sójko
89502bed63 fix(analytics): add missing created at column 2022-11-09 12:41:45 +01:00
12 changed files with 72 additions and 13 deletions

View File

@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.7.2](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.7.1...@standardnotes/analytics@2.7.2) (2022-11-09)
### Bug Fixes
* **analytics:** mrr column types ([90aef90](https://github.com/standardnotes/server/commit/90aef905af05b8c1c86c7bd383df6b2b502f7c91))
## [2.7.1](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.7.0...@standardnotes/analytics@2.7.1) (2022-11-09)
### Bug Fixes
* **analytics:** add missing created at column ([89502be](https://github.com/standardnotes/server/commit/89502bed638b17301e42e0d5916635b0a59f585d))
# [2.7.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.6.0...@standardnotes/analytics@2.7.0) (2022-11-09) # [2.7.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.6.0...@standardnotes/analytics@2.7.0) (2022-11-09)
### Features ### Features

View File

@@ -0,0 +1,13 @@
import { MigrationInterface, QueryRunner } from 'typeorm'
export class addMissingCreatedAt1667994036734 implements MigrationInterface {
name = 'addMissingCreatedAt1667994036734'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query('ALTER TABLE `revenue_modifications` ADD `created_at` bigint NOT NULL')
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query('ALTER TABLE `revenue_modifications` DROP COLUMN `created_at`')
}
}

View File

@@ -0,0 +1,19 @@
import { MigrationInterface, QueryRunner } from 'typeorm'
export class fixMrrFloatingColumns1667995681714 implements MigrationInterface {
name = 'fixMrrFloatingColumns1667995681714'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query('ALTER TABLE `revenue_modifications` DROP COLUMN `previous_mrr`')
await queryRunner.query('ALTER TABLE `revenue_modifications` ADD `previous_mrr` float NOT NULL')
await queryRunner.query('ALTER TABLE `revenue_modifications` DROP COLUMN `new_mrr`')
await queryRunner.query('ALTER TABLE `revenue_modifications` ADD `new_mrr` float NOT NULL')
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query('ALTER TABLE `revenue_modifications` DROP COLUMN `new_mrr`')
await queryRunner.query('ALTER TABLE `revenue_modifications` ADD `new_mrr` int NOT NULL')
await queryRunner.query('ALTER TABLE `revenue_modifications` DROP COLUMN `previous_mrr`')
await queryRunner.query('ALTER TABLE `revenue_modifications` ADD `previous_mrr` int NOT NULL')
}
}

View File

@@ -1,6 +1,6 @@
{ {
"name": "@standardnotes/analytics", "name": "@standardnotes/analytics",
"version": "2.7.0", "version": "2.7.2",
"engines": { "engines": {
"node": ">=14.0.0 <17.0.0" "node": ">=14.0.0 <17.0.0"
}, },

View File

@@ -37,6 +37,7 @@ export class RevenueModificationMap implements MapInterface<RevenueModification,
subscription, subscription,
eventType: SubscriptionEventType.create(persistence.eventType).getValue(), eventType: SubscriptionEventType.create(persistence.eventType).getValue(),
previousMonthlyRevenue: previousMonthlyRevenueOrError.getValue(), previousMonthlyRevenue: previousMonthlyRevenueOrError.getValue(),
createdAt: persistence.createdAt,
}, },
new UniqueEntityId(persistence.uuid), new UniqueEntityId(persistence.uuid),
) )
@@ -55,6 +56,7 @@ export class RevenueModificationMap implements MapInterface<RevenueModification,
persistence.subscriptionPlan = subscription.props.planName.value persistence.subscriptionPlan = subscription.props.planName.value
persistence.userEmail = user.props.email.value persistence.userEmail = user.props.email.value
persistence.userUuid = user.id.toString() persistence.userUuid = user.id.toString()
persistence.createdAt = domain.props.createdAt
return persistence return persistence
} }

View File

@@ -24,6 +24,7 @@ describe('RevenueModification', () => {
it('should create an aggregate for purchased subscription', () => { it('should create an aggregate for purchased subscription', () => {
const revenueModification = RevenueModification.create({ const revenueModification = RevenueModification.create({
createdAt: 2,
eventType: SubscriptionEventType.create('SUBSCRIPTION_PURCHASED').getValue(), eventType: SubscriptionEventType.create('SUBSCRIPTION_PURCHASED').getValue(),
previousMonthlyRevenue: MonthlyRevenue.create(123).getValue(), previousMonthlyRevenue: MonthlyRevenue.create(123).getValue(),
subscription, subscription,
@@ -36,7 +37,7 @@ describe('RevenueModification', () => {
it('should create an aggregate for subscription expired', () => { it('should create an aggregate for subscription expired', () => {
const revenueModification = RevenueModification.create({ const revenueModification = RevenueModification.create({
createdAt: new Date(1), createdAt: 1,
eventType: SubscriptionEventType.create('SUBSCRIPTION_EXPIRED').getValue(), eventType: SubscriptionEventType.create('SUBSCRIPTION_EXPIRED').getValue(),
previousMonthlyRevenue: MonthlyRevenue.create(123).getValue(), previousMonthlyRevenue: MonthlyRevenue.create(123).getValue(),
subscription, subscription,
@@ -49,6 +50,7 @@ describe('RevenueModification', () => {
it('should create an aggregate for subscription cancelled', () => { it('should create an aggregate for subscription cancelled', () => {
const revenueModification = RevenueModification.create({ const revenueModification = RevenueModification.create({
createdAt: 2,
eventType: SubscriptionEventType.create('SUBSCRIPTION_CANCELLED').getValue(), eventType: SubscriptionEventType.create('SUBSCRIPTION_CANCELLED').getValue(),
previousMonthlyRevenue: MonthlyRevenue.create(123).getValue(), previousMonthlyRevenue: MonthlyRevenue.create(123).getValue(),
subscription, subscription,

View File

@@ -9,15 +9,7 @@ export class RevenueModification extends Aggregate<RevenueModificationProps> {
} }
static create(props: RevenueModificationProps, id?: UniqueEntityId): RevenueModification { static create(props: RevenueModificationProps, id?: UniqueEntityId): RevenueModification {
const revenueModification = new RevenueModification( return new RevenueModification(props, id)
{
...props,
createdAt: props.createdAt ? props.createdAt : new Date(),
},
id,
)
return revenueModification
} }
get newMonthlyRevenue(): MonthlyRevenue { get newMonthlyRevenue(): MonthlyRevenue {
@@ -27,6 +19,7 @@ export class RevenueModification extends Aggregate<RevenueModificationProps> {
switch (this.props.eventType.value) { switch (this.props.eventType.value) {
case 'SUBSCRIPTION_PURCHASED': case 'SUBSCRIPTION_PURCHASED':
case 'SUBSCRIPTION_RENEWED': case 'SUBSCRIPTION_RENEWED':
case 'SUBSCRIPTION_DATA_MIGRATED':
revenue = subscription.props.payedAmount / subscription.props.billingFrequency revenue = subscription.props.payedAmount / subscription.props.billingFrequency
break break
case 'SUBSCRIPTION_EXPIRED': case 'SUBSCRIPTION_EXPIRED':

View File

@@ -8,5 +8,5 @@ export interface RevenueModificationProps {
subscription: Subscription subscription: Subscription
eventType: SubscriptionEventType eventType: SubscriptionEventType
previousMonthlyRevenue: MonthlyRevenue previousMonthlyRevenue: MonthlyRevenue
createdAt?: Date createdAt: number
} }

View File

@@ -19,6 +19,7 @@ export class SubscriptionEventType extends ValueObject<SubscriptionEventTypeProp
'SUBSCRIPTION_EXPIRED', 'SUBSCRIPTION_EXPIRED',
'SUBSCRIPTION_REFUNDED', 'SUBSCRIPTION_REFUNDED',
'SUBSCRIPTION_CANCELLED', 'SUBSCRIPTION_CANCELLED',
'SUBSCRIPTION_DATA_MIGRATED',
].includes(subscriptionEventType) ].includes(subscriptionEventType)
) { ) {
return Result.fail<SubscriptionEventType>(`Invalid subscription event type ${subscriptionEventType}`) return Result.fail<SubscriptionEventType>(`Invalid subscription event type ${subscriptionEventType}`)

View File

@@ -1,5 +1,7 @@
import 'reflect-metadata' import 'reflect-metadata'
import { TimerInterface } from '@standardnotes/time'
import { Email } from '../../Common/Email' import { Email } from '../../Common/Email'
import { Uuid } from '../../Common/Uuid' import { Uuid } from '../../Common/Uuid'
import { MonthlyRevenue } from '../../Revenue/MonthlyRevenue' import { MonthlyRevenue } from '../../Revenue/MonthlyRevenue'
@@ -13,8 +15,9 @@ import { SaveRevenueModification } from './SaveRevenueModification'
describe('SaveRevenueModification', () => { describe('SaveRevenueModification', () => {
let revenueModificationRepository: RevenueModificationRepositoryInterface let revenueModificationRepository: RevenueModificationRepositoryInterface
let previousMonthlyRevenue: RevenueModification let previousMonthlyRevenue: RevenueModification
let timer: TimerInterface
const createUseCase = () => new SaveRevenueModification(revenueModificationRepository) const createUseCase = () => new SaveRevenueModification(revenueModificationRepository, timer)
beforeEach(() => { beforeEach(() => {
previousMonthlyRevenue = { previousMonthlyRevenue = {
@@ -24,6 +27,9 @@ describe('SaveRevenueModification', () => {
revenueModificationRepository = {} as jest.Mocked<RevenueModificationRepositoryInterface> revenueModificationRepository = {} as jest.Mocked<RevenueModificationRepositoryInterface>
revenueModificationRepository.findLastByUserUuid = jest.fn().mockReturnValue(previousMonthlyRevenue) revenueModificationRepository.findLastByUserUuid = jest.fn().mockReturnValue(previousMonthlyRevenue)
revenueModificationRepository.save = jest.fn() revenueModificationRepository.save = jest.fn()
timer = {} as jest.Mocked<TimerInterface>
timer.getTimestampInMicroseconds = jest.fn().mockReturnValue(1)
}) })
it('should persist a revenue modification', async () => { it('should persist a revenue modification', async () => {

View File

@@ -9,12 +9,14 @@ import { User } from '../../User/User'
import { Result } from '../../Core/Result' import { Result } from '../../Core/Result'
import { DomainUseCaseInterface } from '../DomainUseCaseInterface' import { DomainUseCaseInterface } from '../DomainUseCaseInterface'
import { SaveRevenueModificationDTO } from './SaveRevenueModificationDTO' import { SaveRevenueModificationDTO } from './SaveRevenueModificationDTO'
import { TimerInterface } from '@standardnotes/time'
@injectable() @injectable()
export class SaveRevenueModification implements DomainUseCaseInterface<RevenueModification> { export class SaveRevenueModification implements DomainUseCaseInterface<RevenueModification> {
constructor( constructor(
@inject(TYPES.RevenueModificationRepository) @inject(TYPES.RevenueModificationRepository)
private revenueModificationRepository: RevenueModificationRepositoryInterface, private revenueModificationRepository: RevenueModificationRepositoryInterface,
@inject(TYPES.Timer) private timer: TimerInterface,
) {} ) {}
async execute(dto: SaveRevenueModificationDTO): Promise<Result<RevenueModification>> { async execute(dto: SaveRevenueModificationDTO): Promise<Result<RevenueModification>> {
@@ -45,6 +47,7 @@ export class SaveRevenueModification implements DomainUseCaseInterface<RevenueMo
subscription, subscription,
user, user,
previousMonthlyRevenue, previousMonthlyRevenue,
createdAt: this.timer.getTimestampInMicroseconds(),
}) })
await this.revenueModificationRepository.save(revenueModification) await this.revenueModificationRepository.save(revenueModification)

View File

@@ -49,11 +49,19 @@ export class TypeORMRevenueModification {
@Column({ @Column({
name: 'previous_mrr', name: 'previous_mrr',
type: 'float',
}) })
declare previousMonthlyRevenue: number declare previousMonthlyRevenue: number
@Column({ @Column({
name: 'new_mrr', name: 'new_mrr',
type: 'float',
}) })
declare newMonthlyRevenue: number declare newMonthlyRevenue: number
@Column({
name: 'created_at',
type: 'bigint',
})
declare createdAt: number
} }