ref #65: new formula functions ACCRINTM and AMORDEGRC
This commit is contained in:
parent
cf8766df83
commit
c89b64c53c
147
calc.go
147
calc.go
|
@ -261,10 +261,12 @@ type formulaFuncs struct {
|
|||
// Supported formula functions:
|
||||
//
|
||||
// ABS
|
||||
// ACCRINTM
|
||||
// ACOS
|
||||
// ACOSH
|
||||
// ACOT
|
||||
// ACOTH
|
||||
// AMORDEGRC
|
||||
// AND
|
||||
// ARABIC
|
||||
// ASIN
|
||||
|
@ -8312,6 +8314,151 @@ func (fn *formulaFuncs) ENCODEURL(argsList *list.List) formulaArg {
|
|||
|
||||
// Financial Functions
|
||||
|
||||
// ACCRINTM function returns the accrued interest for a security that pays
|
||||
// interest at maturity. The syntax of the function is:
|
||||
//
|
||||
// ACCRINTM(issue,settlement,rate,[par],[basis])
|
||||
//
|
||||
func (fn *formulaFuncs) ACCRINTM(argsList *list.List) formulaArg {
|
||||
if argsList.Len() != 4 && argsList.Len() != 5 {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, "ACCRINTM requires 4 or 5 arguments")
|
||||
}
|
||||
args := list.New().Init()
|
||||
args.PushBack(argsList.Front().Value.(formulaArg))
|
||||
issue := fn.DATEVALUE(args)
|
||||
if issue.Type != ArgNumber {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
|
||||
}
|
||||
args.Init()
|
||||
args.PushBack(argsList.Front().Next().Value.(formulaArg))
|
||||
settlement := fn.DATEVALUE(args)
|
||||
if settlement.Type != ArgNumber {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
|
||||
}
|
||||
if settlement.Number < issue.Number {
|
||||
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
|
||||
}
|
||||
rate := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
|
||||
par := argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber()
|
||||
if rate.Type != ArgNumber || par.Type != ArgNumber {
|
||||
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
|
||||
}
|
||||
if par.Number <= 0 {
|
||||
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
|
||||
}
|
||||
basis := newNumberFormulaArg(0)
|
||||
if argsList.Len() == 5 {
|
||||
if basis = argsList.Back().Value.(formulaArg).ToNumber(); basis.Type != ArgNumber {
|
||||
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
|
||||
}
|
||||
}
|
||||
frac := yearFrac(issue.Number, settlement.Number, int(basis.Number))
|
||||
if frac.Type != ArgNumber {
|
||||
return frac
|
||||
}
|
||||
return newNumberFormulaArg(frac.Number * rate.Number * par.Number)
|
||||
}
|
||||
|
||||
// prepareAmorArgs checking and prepare arguments for the formula functions
|
||||
// AMORDEGRC and AMORLINC.
|
||||
func (fn *formulaFuncs) prepareAmorArgs(name string, argsList *list.List) formulaArg {
|
||||
cost := argsList.Front().Value.(formulaArg).ToNumber()
|
||||
if cost.Type != ArgNumber {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires cost to be number argument", name))
|
||||
}
|
||||
if cost.Number < 0 {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires cost >= 0", name))
|
||||
}
|
||||
args := list.New().Init()
|
||||
args.PushBack(argsList.Front().Next().Value.(formulaArg))
|
||||
datePurchased := fn.DATEVALUE(args)
|
||||
if datePurchased.Type != ArgNumber {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
|
||||
}
|
||||
args.Init()
|
||||
args.PushBack(argsList.Front().Next().Next().Value.(formulaArg))
|
||||
firstPeriod := fn.DATEVALUE(args)
|
||||
if firstPeriod.Type != ArgNumber {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
|
||||
}
|
||||
if firstPeriod.Number < datePurchased.Number {
|
||||
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
|
||||
}
|
||||
salvage := argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber()
|
||||
if salvage.Type != ArgNumber {
|
||||
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
|
||||
}
|
||||
if salvage.Number < 0 || salvage.Number > cost.Number {
|
||||
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
|
||||
}
|
||||
period := argsList.Front().Next().Next().Next().Next().Value.(formulaArg).ToNumber()
|
||||
if period.Type != ArgNumber || period.Number < 0 {
|
||||
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
|
||||
}
|
||||
rate := argsList.Front().Next().Next().Next().Next().Next().Value.(formulaArg).ToNumber()
|
||||
if rate.Type != ArgNumber || rate.Number < 0 {
|
||||
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
|
||||
}
|
||||
basis := newNumberFormulaArg(0)
|
||||
if argsList.Len() == 7 {
|
||||
if basis = argsList.Back().Value.(formulaArg).ToNumber(); basis.Type != ArgNumber {
|
||||
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
|
||||
}
|
||||
}
|
||||
return newListFormulaArg([]formulaArg{cost, datePurchased, firstPeriod, salvage, period, rate, basis})
|
||||
}
|
||||
|
||||
// AMORDEGRC function is provided for users of the French accounting system.
|
||||
// The function calculates the prorated linear depreciation of an asset for a
|
||||
// specified accounting period. The syntax of the function is:
|
||||
//
|
||||
// AMORDEGRC(cost,date_purchased,first_period,salvage,period,rate,[basis])
|
||||
//
|
||||
func (fn *formulaFuncs) AMORDEGRC(argsList *list.List) formulaArg {
|
||||
if argsList.Len() != 6 && argsList.Len() != 7 {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, "AMORDEGRC requires 6 or 7 arguments")
|
||||
}
|
||||
args := fn.prepareAmorArgs("AMORDEGRC", argsList)
|
||||
if args.Type != ArgList {
|
||||
return args
|
||||
}
|
||||
cost, datePurchased, firstPeriod, salvage, period, rate, basis := args.List[0], args.List[1], args.List[2], args.List[3], args.List[4], args.List[5], args.List[6]
|
||||
if rate.Number >= 0.5 {
|
||||
return newErrorFormulaArg(formulaErrorNUM, "AMORDEGRC requires rate to be < 0.5")
|
||||
}
|
||||
assetsLife, amorCoeff := 1/rate.Number, 2.5
|
||||
if assetsLife < 3 {
|
||||
amorCoeff = 1
|
||||
} else if assetsLife < 5 {
|
||||
amorCoeff = 1.5
|
||||
} else if assetsLife <= 6 {
|
||||
amorCoeff = 2
|
||||
}
|
||||
rate.Number *= amorCoeff
|
||||
frac := yearFrac(datePurchased.Number, firstPeriod.Number, int(basis.Number))
|
||||
if frac.Type != ArgNumber {
|
||||
return frac
|
||||
}
|
||||
nRate := float64(int((frac.Number * cost.Number * rate.Number) + 0.5))
|
||||
cost.Number -= nRate
|
||||
rest := cost.Number - salvage.Number
|
||||
for n := 0; n < int(period.Number); n++ {
|
||||
nRate = float64(int((cost.Number * rate.Number) + 0.5))
|
||||
rest -= nRate
|
||||
if rest < 0 {
|
||||
switch int(period.Number) - n {
|
||||
case 0:
|
||||
case 1:
|
||||
return newNumberFormulaArg(float64(int((cost.Number * 0.5) + 0.5)))
|
||||
default:
|
||||
return newNumberFormulaArg(0)
|
||||
}
|
||||
}
|
||||
cost.Number -= nRate
|
||||
}
|
||||
return newNumberFormulaArg(nRate)
|
||||
}
|
||||
|
||||
// CUMIPMT function calculates the cumulative interest paid on a loan or
|
||||
// investment, between two specified periods. The syntax of the function is:
|
||||
//
|
||||
|
|
36
calc_test.go
36
calc_test.go
|
@ -1232,6 +1232,16 @@ func TestCalcCellValue(t *testing.T) {
|
|||
// ENCODEURL
|
||||
"=ENCODEURL(\"https://xuri.me/excelize/en/?q=Save As\")": "https%3A%2F%2Fxuri.me%2Fexcelize%2Fen%2F%3Fq%3DSave%20As",
|
||||
// Financial Functions
|
||||
// ACCRINTM
|
||||
"=ACCRINTM(\"01/01/2012\",\"12/31/2012\",8%,10000)": "800",
|
||||
"=ACCRINTM(\"01/01/2012\",\"12/31/2012\",8%,10000,3)": "800",
|
||||
// AMORDEGRC
|
||||
"=AMORDEGRC(150,\"01/01/2015\",\"09/30/2015\",20,1,20%)": "42",
|
||||
"=AMORDEGRC(150,\"01/01/2015\",\"09/30/2015\",20,1,20%,4)": "42",
|
||||
"=AMORDEGRC(150,\"01/01/2015\",\"09/30/2015\",20,1,40%,4)": "42",
|
||||
"=AMORDEGRC(150,\"01/01/2015\",\"09/30/2015\",20,1,25%,4)": "41",
|
||||
"=AMORDEGRC(150,\"01/01/2015\",\"09/30/2015\",109,1,25%,4)": "54",
|
||||
"=AMORDEGRC(150,\"01/01/2015\",\"09/30/2015\",110,2,25%,4)": "0",
|
||||
// CUMIPMT
|
||||
"=CUMIPMT(0.05/12,60,50000,1,12,0)": "-2294.97753732664",
|
||||
"=CUMIPMT(0.05/12,60,50000,13,24,0)": "-1833.1000665738893",
|
||||
|
@ -2291,6 +2301,32 @@ func TestCalcCellValue(t *testing.T) {
|
|||
// ENCODEURL
|
||||
"=ENCODEURL()": "ENCODEURL requires 1 argument",
|
||||
// Financial Functions
|
||||
// ACCRINTM
|
||||
"=ACCRINTM()": "ACCRINTM requires 4 or 5 arguments",
|
||||
"=ACCRINTM(\"\",\"01/01/2012\",8%,10000)": "#VALUE!",
|
||||
"=ACCRINTM(\"01/01/2012\",\"\",8%,10000)": "#VALUE!",
|
||||
"=ACCRINTM(\"12/31/2012\",\"01/01/2012\",8%,10000)": "#NUM!",
|
||||
"=ACCRINTM(\"01/01/2012\",\"12/31/2012\",\"\",10000)": "#NUM!",
|
||||
"=ACCRINTM(\"01/01/2012\",\"12/31/2012\",8%,\"\",10000)": "#NUM!",
|
||||
"=ACCRINTM(\"01/01/2012\",\"12/31/2012\",8%,-1,10000)": "#NUM!",
|
||||
"=ACCRINTM(\"01/01/2012\",\"12/31/2012\",8%,10000,\"\")": "#NUM!",
|
||||
"=ACCRINTM(\"01/01/2012\",\"12/31/2012\",8%,10000,5)": "invalid basis",
|
||||
// AMORDEGRC
|
||||
"=AMORDEGRC()": "AMORDEGRC requires 6 or 7 arguments",
|
||||
"=AMORDEGRC(\"\",\"01/01/2015\",\"09/30/2015\",20,1,20%)": "AMORDEGRC requires cost to be number argument",
|
||||
"=AMORDEGRC(-1,\"01/01/2015\",\"09/30/2015\",20,1,20%)": "AMORDEGRC requires cost >= 0",
|
||||
"=AMORDEGRC(150,\"\",\"09/30/2015\",20,1,20%)": "#VALUE!",
|
||||
"=AMORDEGRC(150,\"01/01/2015\",\"\",20,1,20%)": "#VALUE!",
|
||||
"=AMORDEGRC(150,\"09/30/2015\",\"01/01/2015\",20,1,20%)": "#NUM!",
|
||||
"=AMORDEGRC(150,\"01/01/2015\",\"09/30/2015\",\"\",1,20%)": "#NUM!",
|
||||
"=AMORDEGRC(150,\"01/01/2015\",\"09/30/2015\",-1,1,20%)": "#NUM!",
|
||||
"=AMORDEGRC(150,\"01/01/2015\",\"09/30/2015\",20,\"\",20%)": "#NUM!",
|
||||
"=AMORDEGRC(150,\"01/01/2015\",\"09/30/2015\",20,-1,20%)": "#NUM!",
|
||||
"=AMORDEGRC(150,\"01/01/2015\",\"09/30/2015\",20,1,\"\")": "#NUM!",
|
||||
"=AMORDEGRC(150,\"01/01/2015\",\"09/30/2015\",20,1,-1)": "#NUM!",
|
||||
"=AMORDEGRC(150,\"01/01/2015\",\"09/30/2015\",20,1,20%,\"\")": "#NUM!",
|
||||
"=AMORDEGRC(150,\"01/01/2015\",\"09/30/2015\",20,1,50%)": "AMORDEGRC requires rate to be < 0.5",
|
||||
"=AMORDEGRC(150,\"01/01/2015\",\"09/30/2015\",20,1,20%,5)": "invalid basis",
|
||||
// CUMIPMT
|
||||
"=CUMIPMT()": "CUMIPMT requires 6 arguments",
|
||||
"=CUMIPMT(0,0,0,0,0,2)": "#N/A",
|
||||
|
|
Loading…
Reference in New Issue