Skip to content
This repository was archived by the owner on Sep 27, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
7324005
Improve entities
akiomik Dec 8, 2021
42f24e9
Use v3 endpoint in csv exporter
akiomik Dec 8, 2021
5574bcc
Merge pull request #61 from BuffettCode/use-v3-endpoint-in-csv-exporter
akiomik Dec 10, 2021
9a170dd
Add object support to BcodeResult v3
akiomik Dec 8, 2021
34786a0
Add object format support to csv exporter
akiomik Dec 8, 2021
4b6bb8b
Merge pull request #62 from BuffettCode/fix-segment-member
akiomik Dec 10, 2021
3b2c15d
Fix company v3
akiomik Dec 13, 2021
0085b44
Merge pull request #65 from BuffettCode/fix-company-v3
akiomik Dec 13, 2021
c5cafe3
Add YYYYLQ and LYQn support to quarter params
akiomik Dec 10, 2021
0e62dac
Add advanced LY/LQ support
akiomik Dec 15, 2021
52be435
Merge pull request #63 from BuffettCode/add-advanced-ly-lq-support
akiomik Dec 15, 2021
c0127c7
Improve HttpError message
akiomik Dec 22, 2021
4d20be1
Improve InvaliYearError and InvaliQuarterError message
akiomik Dec 22, 2021
eba4e0a
Merge pull request #67 from BuffettCode/improve-error-message
akiomik Dec 24, 2021
9750512
Add LqWithOffset and LyWithOffset
akiomik Dec 15, 2021
60af13e
Add relative LY LQ support
akiomik Dec 15, 2021
cf713bf
Merge pull request #66 from BuffettCode/add-relative-ly-lq-support
akiomik Dec 24, 2021
454f7cb
Update release document
akiomik Dec 24, 2021
9fdebc1
Merge pull request #69 from BuffettCode/update-release-document
akiomik Dec 24, 2021
f911f35
Bump version to v11
akiomik Dec 24, 2021
bbf278c
Merge pull request #70 from BuffettCode/bump-version-to-11
akiomik Dec 24, 2021
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: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,5 @@ npm run deploy:prod
1. Edit `src/version.ts`.
2. Merge development branch into master.
3. Create a release on github.
3. Create Deployments from `Publish` -> `Deploy from manifest` in script editor for prodcution.
4. Run `git checkout master && npm run deploy:prod` to deploy master branch.
5. Create Deployments from `Publish` -> `Deploy from manifest` in script editor for prodcution.
2 changes: 1 addition & 1 deletion src/__mocks__/fixtures/v3/quarter.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ module.exports = {
employee_num: null,
net_sales_per_employee: null,
operating_income_per_employee: null,
segment_member: null,
segment_member: {"segments":[],"periods":[],"values":[]},
increase_in_properties: 346000000,
r_and_d_expenses: 35000000,
defined_benefit_asset: null,
Expand Down
77 changes: 76 additions & 1 deletion src/api/company-service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@ import { CompanyService } from '~/api/company-service'
import { CachingBuffettCodeApiClientV2 } from '~/api/v2/caching-client'
import { CachingBuffettCodeApiClientV3 } from '~/api/v3/caching-client'
import { DateParam } from '~/fiscal-periods/date-param'
import { LqWithOffset } from '~/fiscal-periods/lq-with-offset'
import { LyWithOffset } from '~/fiscal-periods/ly-with-offset'
import { YearQuarter } from '~/fiscal-periods/year-quarter'
import { YearQuarterParam } from '~/fiscal-periods/year-quarter-param'

const LY = new LyWithOffset()
const LQ = new LqWithOffset()

jest.mock('~/api/v2/client', () =>
jest.requireActual('~/__mocks__/api/v2/client')
)
Expand All @@ -21,6 +26,55 @@ test('isSupportedTicker', () => {
expect(new CompanyService('9999', client).isSupportedTicker()).toBe(false)
})

test('convertYearQuarterParamToYearQuarter', () => {
const client = new CachingBuffettCodeApiClientV2('token')
const service = new CompanyService('2371', client)
expect(
service.convertYearQuarterParamToYearQuarter(new YearQuarterParam(LY, 3))
).toEqual(new YearQuarter(2021, 3))
expect(
service.convertYearQuarterParamToYearQuarter(new YearQuarterParam(2016, LQ))
).toEqual(new YearQuarter(2016, 2))
expect(
service.convertYearQuarterParamToYearQuarter(new YearQuarterParam(LY, LQ))
).toEqual(new YearQuarter(2021, 2))
expect(
service.convertYearQuarterParamToYearQuarter(
new YearQuarterParam(new LyWithOffset(-5), LQ)
)
).toEqual(new YearQuarter(2016, 2))
expect(
service.convertYearQuarterParamToYearQuarter(
new YearQuarterParam(LY, new LqWithOffset(-1))
)
).toEqual(new YearQuarter(2021, 1))
expect(
service.convertYearQuarterParamToYearQuarter(
new YearQuarterParam(LY, new LqWithOffset(-2))
)
).toEqual(new YearQuarter(2020, 4))
expect(
service.convertYearQuarterParamToYearQuarter(
new YearQuarterParam(LY, new LqWithOffset(-3))
)
).toEqual(new YearQuarter(2020, 3))
expect(
service.convertYearQuarterParamToYearQuarter(
new YearQuarterParam(LY, new LqWithOffset(-4))
)
).toEqual(new YearQuarter(2020, 2))
expect(
service.convertYearQuarterParamToYearQuarter(
new YearQuarterParam(LY, new LqWithOffset(-5))
)
).toEqual(new YearQuarter(2020, 1))
expect(
service.convertYearQuarterParamToYearQuarter(
new YearQuarterParam(new LyWithOffset(-5), new LqWithOffset(-5))
)
).toEqual(new YearQuarter(2015, 1))
})

test('isOndemandQuarterApiPeriod', () => {
const client = new CachingBuffettCodeApiClientV2('token')
const service = new CompanyService('2371', client)
Expand All @@ -34,9 +88,30 @@ test('isOndemandQuarterApiPeriod', () => {
expect(service.isOndemandQuarterApiPeriod(new YearQuarter(2016, 3))).toBe(
false
)
expect(service.isOndemandQuarterApiPeriod(new YearQuarterParam(LY, 3))).toBe(
false
)
expect(
service.isOndemandQuarterApiPeriod(new YearQuarterParam(2016, LQ))
).toBe(true)
expect(service.isOndemandQuarterApiPeriod(new YearQuarterParam(LY, LQ))).toBe(
false
)
expect(
service.isOndemandQuarterApiPeriod(new YearQuarterParam('LY', 'LQ'))
service.isOndemandQuarterApiPeriod(
new YearQuarterParam(new LyWithOffset(-4), new LqWithOffset(-3))
)
).toBe(false)
expect(
service.isOndemandQuarterApiPeriod(
new YearQuarterParam(new LyWithOffset(-4), new LqWithOffset(-4))
)
).toBe(true)
expect(
service.isOndemandQuarterApiPeriod(
new YearQuarterParam(new LyWithOffset(-5), LQ)
)
).toBe(true)
})

test('isOndemandDailyApiPeriod', () => {
Expand Down
32 changes: 26 additions & 6 deletions src/api/company-service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { BuffettCodeApiClientV2 } from '~/api/v2/client'
import { BuffettCodeApiClientV3 } from '~/api/v3/client'
import { DateParam } from '~/fiscal-periods/date-param'
import { LqWithOffset } from '~/fiscal-periods/lq-with-offset'
import { LyWithOffset } from '~/fiscal-periods/ly-with-offset'
import { YearQuarter } from '~/fiscal-periods/year-quarter'
import { YearQuarterParam } from '~/fiscal-periods/year-quarter-param'

Expand All @@ -19,20 +21,38 @@ export class CompanyService {
return !!this.company
}

public convertYearQuarterParamToYearQuarter(
period: YearQuarterParam
): YearQuarter {
if (period.year instanceof LyWithOffset) {
period.year = this.company['latest_fiscal_year'] + period.year.offset
}

if (period.quarter instanceof LqWithOffset) {
period.year =
(period.year as number) + Math.ceil(period.quarter.offset / 4)
period.quarter =
this.company['latest_fiscal_quarter'] + (period.quarter.offset % 4)

if (period.quarter <= 0) {
period.year -= 1
period.quarter = 4 + (period.quarter as number)
}
}

return period.toYearQuarter()
}

public isOndemandQuarterApiPeriod(
_period: YearQuarter | YearQuarterParam
): boolean {
if (!this.isSupportedTicker()) {
throw new Error('unsupported ticker')
}

let period
let period: YearQuarter
if (_period instanceof YearQuarterParam) {
if (_period.isLatestYear() && _period.isLatestQuarter()) {
return false
}

period = _period.toYearQuarter()
period = this.convertYearQuarterParamToYearQuarter(_period)
} else {
period = _period
}
Expand Down
2 changes: 1 addition & 1 deletion src/api/http-error.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ import { useMockedUrlFetchApp } from '~/api/test-helper'

test('HttpError', () => {
const res = useMockedUrlFetchApp(403, '{"message": "Forbidden"}')()
const error = new HttpError(res)
const error = new HttpError('https://example.com', res)
expect(error instanceof HttpError).toBeTruthy()
})
8 changes: 5 additions & 3 deletions src/api/http-error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ export class HttpError implements Error {
public name = 'HttpError'
public message: string

// eslint-disable-next-line @typescript-eslint/camelcase
constructor(public response: GoogleAppsScript.URL_Fetch.HTTPResponse) {
this.message = `${response.getResponseCode()}: ${response.getContentText()}`
constructor(
public url: string,
public response: GoogleAppsScript.URL_Fetch.HTTPResponse // eslint-disable-line @typescript-eslint/camelcase
) {
this.message = `${url} - ${response.getResponseCode()}: ${response.getContentText()}`
}

public isInvalidTestingRequest(): boolean {
Expand Down
9 changes: 7 additions & 2 deletions src/api/v2/caching-client.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { CompanyCache } from '~/__mocks__/services/company-cache'
import { QuarterCache } from '~/__mocks__/services/quarter-cache'
import { CachingBuffettCodeApiClientV2 } from '~/api/v2/caching-client'
import { LqWithOffset } from '~/fiscal-periods/lq-with-offset'
import { LyWithOffset } from '~/fiscal-periods/ly-with-offset'
import { YearQuarter } from '~/fiscal-periods/year-quarter'
import { YearQuarterParam } from '~/fiscal-periods/year-quarter-param'
import { IndicatorCache } from '~/services/indicator-cache'
Expand All @@ -18,6 +20,9 @@ jest.mock('~/services/quarter-cache', () =>
jest.requireActual('~/__mocks__/services/quarter-cache')
)

const LY = new LyWithOffset()
const LQ = new LqWithOffset()

describe('company', () => {
const ticker = '2371'

Expand Down Expand Up @@ -111,7 +116,7 @@ describe('quarter', () => {
QuarterCache.clearAll()
})

const period = new YearQuarterParam('LY', 'LQ')
const period = new YearQuarterParam(LY, LQ)

test('(uncached)', () => {
expect(QuarterCache.getData(ticker, new YearQuarter(2018, 1))).toBeNull()
Expand Down Expand Up @@ -168,7 +173,7 @@ describe('ondemandQuarter', () => {
QuarterCache.clearAll()
})

const period = new YearQuarterParam('LY', 'LQ')
const period = new YearQuarterParam(LY, LQ)

test('(uncached)', () => {
expect(QuarterCache.getData(ticker, new YearQuarter(2018, 1))).toBeNull()
Expand Down
4 changes: 2 additions & 2 deletions src/api/v2/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ test('HttpError#isInvalidTestingRequest', () => {
200,
'{"message":"Testing Apikey is only allowed to ticker ending with \\"01\\""}'
)()
const error1 = new HttpError(res1)
const error1 = new HttpError('https://example.com', res1)
expect(error1.isInvalidTestingRequest()).toBeTruthy()

const res2 = useMockedUrlFetchApp(403, '{"message": "Forbidden"}')()
const error2 = new HttpError(res2)
const error2 = new HttpError('https://example.com', res2)
expect(error2.isInvalidTestingRequest()).toBeFalsy()
})

Expand Down
6 changes: 3 additions & 3 deletions src/api/v2/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export class BuffettCodeApiClientV2 {

const code = res.getResponseCode()
const content = res.getContentText()
const error = new HttpError(res)
const error = new HttpError(url, res)
if (
Math.floor(code / 100) === 4 ||
Math.floor(code / 100) === 5 ||
Expand All @@ -29,8 +29,8 @@ export class BuffettCodeApiClientV2 {
try {
json = JSON.parse(content)
} catch (e) {
console.error('JSON parsing error', code, content)
throw new HttpError(res)
console.error('JSON parsing error', url, code, content)
throw new HttpError(url, res)
}

return json
Expand Down
9 changes: 7 additions & 2 deletions src/api/v3/caching-client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { DailyCache } from '~/__mocks__/services/daily-cache'
import { QuarterCache } from '~/__mocks__/services/quarter-cache'
import { CachingBuffettCodeApiClientV3 } from '~/api/v3/caching-client'
import { DateParam } from '~/fiscal-periods/date-param'
import { LqWithOffset } from '~/fiscal-periods/lq-with-offset'
import { LyWithOffset } from '~/fiscal-periods/ly-with-offset'
import { YearQuarter } from '~/fiscal-periods/year-quarter'
import { YearQuarterParam } from '~/fiscal-periods/year-quarter-param'

Expand All @@ -19,6 +21,9 @@ jest.mock('~/services/quarter-cache', () =>
jest.requireActual('~/__mocks__/services/quarter-cache')
)

const LY = new LyWithOffset()
const LQ = new LqWithOffset()

describe('company', () => {
const ticker = '2371'

Expand Down Expand Up @@ -112,7 +117,7 @@ describe('quarter', () => {
QuarterCache.clearAll()
})

const period = new YearQuarterParam('LY', 'LQ')
const period = new YearQuarterParam(LY, LQ)

test('(uncached)', () => {
expect(QuarterCache.get(ticker, new YearQuarter(2018, 1))).toBeNull()
Expand Down Expand Up @@ -165,7 +170,7 @@ describe('ondemandQuarter', () => {
QuarterCache.clearAll()
})

const period = new YearQuarterParam('LY', 'LQ')
const period = new YearQuarterParam(LY, LQ)

test('(uncached)', () => {
expect(QuarterCache.get(ticker, new YearQuarter(2018, 1))).toBeNull()
Expand Down
32 changes: 28 additions & 4 deletions src/api/v3/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { Daily } from '~/entities/v3/daily'
import { Quarter } from '~/entities/v3/quarter'
import { DateParam } from '~/fiscal-periods/date-param'
import { DateRange } from '~/fiscal-periods/date-range'
import { LqWithOffset } from '~/fiscal-periods/lq-with-offset'
import { LyWithOffset } from '~/fiscal-periods/ly-with-offset'
import { YearQuarter } from '~/fiscal-periods/year-quarter'
import { YearQuarterParam } from '~/fiscal-periods/year-quarter-param'
import { YearQuarterRange } from '~/fiscal-periods/year-quarter-range'
Expand All @@ -18,11 +20,11 @@ describe('BuffettCodeApiClientV3', () => {
200,
'{"message":"Testing apikey is not allowed"}'
)()
const error1 = new HttpError(res1)
const error1 = new HttpError('https://example.com', res1)
expect(error1.isInvalidTestingRequest()).toBeTruthy()

const res2 = useMockedUrlFetchApp(403, '{"message": "Forbidden"}')()
const error2 = new HttpError(res2)
const error2 = new HttpError('https://example.com', res2)
expect(error2.isInvalidTestingRequest()).toBeFalsy()
})

Expand Down Expand Up @@ -85,7 +87,7 @@ describe('BuffettCodeApiClientV3', () => {

const client = new BuffettCodeApiClientV3('foo')
const ticker = '2371'
expect(client.company(ticker)).toEqual(company[ticker])
expect(client.company(ticker)).toEqual(company['data'])
expect(mockFetch.mock.calls.length).toBe(1)
expect(mockFetch.mock.calls[0].length).toBe(2)
expect(mockFetch.mock.calls[0][0]).toBe(
Expand All @@ -97,7 +99,7 @@ describe('BuffettCodeApiClientV3', () => {
})
})

test('quarter', () => {
test('quarter (FY/FQ)', () => {
const mockFetch = useMockedUrlFetchApp(200, JSON.stringify(quarter))

const client = new BuffettCodeApiClientV3('foo')
Expand All @@ -117,6 +119,28 @@ describe('BuffettCodeApiClientV3', () => {
})
})

test('quarter (LY/LQ)', () => {
const mockFetch = useMockedUrlFetchApp(200, JSON.stringify(quarter))

const LY = new LyWithOffset()
const LQ = new LqWithOffset()
const client = new BuffettCodeApiClientV3('foo')
const ticker = '2371'
const period = new YearQuarterParam(LY, LQ)
expect(client.quarter(ticker, period)).toEqual(
Quarter.fromResponse(quarter)
)
expect(mockFetch.mock.calls.length).toBe(1)
expect(mockFetch.mock.calls[0].length).toBe(2)
expect(mockFetch.mock.calls[0][0]).toBe(
'https://api.buffett-code.com/api/v3/quarter?ticker=2371&fy=LY&fq=LQ'
)
expect(mockFetch.mock.calls[0][1]).toEqual({
headers: { 'x-api-key': 'foo' },
muteHttpExceptions: true
})
})

test('bulkQuarter', () => {
const bulkQuarter = {
data: {
Expand Down
Loading