From 5ea7f5d13cf6eae59e733159878f5555acd6fa6b Mon Sep 17 00:00:00 2001 From: Softonik Date: Tue, 25 Jun 2024 18:03:31 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9D=D0=B0=D1=87=D0=B0=D0=BB=D0=BE:=20=D0=BC?= =?UTF-8?q?=D0=BE=D0=B4=D1=83=D0=BB=D1=8C=20=D1=81=D1=87=D1=91=D1=82=D0=B0?= =?UTF-8?q?=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/schet/celi.go | 30 ++++++++++++ pkg/schet/features/app.feature | 82 +++++++++++++++++++++++++++++++++ pkg/schet/helpers.go | 11 +++++ pkg/schet/init_test.go | 61 ++++++++++++++++++++++++ pkg/schet/kvartal.go | 49 ++++++++++++++++++++ pkg/schet/ops.go | 18 ++++++++ pkg/schet/out.go | 5 ++ pkg/schet/schet.go | 77 +++++++++++++++++++++++++++++++ pkg/schet/schet_test.go | 84 ++++++++++++++++++++++++++++++++++ pkg/schet/summator300tr.go | 53 +++++++++++++++++++++ pkg/schet/ucn.go | 18 ++++++++ 11 files changed, 488 insertions(+) create mode 100644 pkg/schet/celi.go create mode 100644 pkg/schet/features/app.feature create mode 100644 pkg/schet/helpers.go create mode 100644 pkg/schet/init_test.go create mode 100644 pkg/schet/kvartal.go create mode 100644 pkg/schet/ops.go create mode 100644 pkg/schet/out.go create mode 100644 pkg/schet/schet.go create mode 100644 pkg/schet/schet_test.go create mode 100644 pkg/schet/summator300tr.go create mode 100644 pkg/schet/ucn.go diff --git a/pkg/schet/celi.go b/pkg/schet/celi.go new file mode 100644 index 0000000..75c0aba --- /dev/null +++ b/pkg/schet/celi.go @@ -0,0 +1,30 @@ +package schet + +import ( + "errors" +) + +type Цели struct { + год *Год + Кварталы []*Квартал +} + +func NewЦели(год *Год) *Цели { + c := &Цели{ + год: год, + } + return c +} + +func (c *Цели) Квартал(in int) (k *Квартал, e error) { + e = errors.New("неизвестный квартал") + + if in < НомерПервогоКвартала || in > НомерПоследнегоКвартала { + return + } + + index := in - 1 + k = c.Кварталы[index] + e = nil + return +} diff --git a/pkg/schet/features/app.feature b/pkg/schet/features/app.feature new file mode 100644 index 0000000..341cb72 --- /dev/null +++ b/pkg/schet/features/app.feature @@ -0,0 +1,82 @@ +# Во имя Бога Милостивого, Милосердного!!! +# language: ru +Функциональность: Счёт + + Сценарий: Платёж по ОПС в квартале + Дано Год: 2024 + Дано Квартал: <квартал> + Когда Расчитать год + То Есть цель: ОПС за этот квартал: 12375 + + Примеры: + | квартал | + | 1 | + | 2 | + | 3 | + | 4 | + + Сценарий: Платёж 1% сверх 300тр: в год и за 1-ый квартал + Дано Год: 2024 + Дано Квартал: 1 + Дано Доход: <доход> + Когда Расчитать год + То Есть цель: 1% сверх 300тр за квартал: "<оплатить_за_квартал>" + То Есть цель: 1% сверх 300тр за год: "<оплатить_за_год>" + + Примеры: + | доход | оплатить_за_квартал | оплатить_за_год | + | 0 | 0 | 0 | + | 300000 | 0 | 0 | + | 300001 | 0 | 0 | + | 300049 | 0 | 0 | + | 300050 | 1 | 1 | + | 300051 | 1 | 1 | + | 300100 | 1 | 1 | + | 300200 | 2 | 2 | + | 400000 | 1000 | 1000 | + | 500000 | 2000 | 2000 | + + Сценарий: Платёж 1% сверх 300тр: в год и за все кварталы + Дано Год: 2024 + Дано Доход <доход1> за 1 квартал + Дано Доход <доход2> за 2 квартал + Дано Доход <доход3> за 3 квартал + Дано Доход <доход4> за 4 квартал + Когда Расчитать год + То Есть цель: 1% сверх 300тр за 1 квартал: "<оплатить1>" + То Есть цель: 1% сверх 300тр за 2 квартал: "<оплатить2>" + То Есть цель: 1% сверх 300тр за 3 квартал: "<оплатить3>" + То Есть цель: 1% сверх 300тр за 4 квартал: "<оплатить4>" + То Есть цель: 1% сверх 300тр за год: "<оплатить_за_год>" + + Примеры: + | доход1 | оплатить1 | доход2 | оплатить2 | доход3 | оплатить3 | доход4 | оплатить4 | оплатить_за_год | + | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | + | 100000 | 0 | 100000 | 0 | 0 | 0 | 0 | 0 | 0 | + | 100000 | 0 | 100000 | 0 | 100000 | 0 | 0 | 0 | 0 | + | 1000 | 0 | 90000 | 0 | 100000 | 0 | 100000 | 0 | 0 | + | 100000 | 0 | 250000 | 500 | 0 | 0 | 0 | 0 | 500 | + | 100000 | 0 | 100000 | 0 | 100000 | 0 | 100000 | 1000 | 1000 | + | 100000 | 0 | 100000 | 0 | 200000 | 1000 | 100000 | 1000 | 2000 | + | 100000 | 0 | 250000 | 500 | 400000 | 4000 | 0 | 0 | 4500 | + | 100000 | 0 | 250000 | 500 | 400000 | 4000 | 500000 | 5000 | 9500 | + | 400000 | 1000 | 0 | 0 | 0 | 0 | 0 | 0 | 1000 | + | 0 | 0 | 400000 | 1000 | 0 | 0 | 0 | 0 | 1000 | + | 0 | 0 | 0 | 0 | 400000 | 1000 | 0 | 0 | 1000 | + | 0 | 0 | 0 | 0 | 0 | 0 | 400000 | 1000 | 1000 | + | 400000 | 1000 | 100000 | 1000 | 0 | 0 | 0 | 0 | 2000 | + | 400000 | 1000 | 500000 | 5000 | 600000 | 6000 | 700000 | 7000 | 19000 | + + Сценарий: Платёж по УСН в квартале: 4% + Дано Год: 2024 + Дано Квартал: <квартал> + Дано Доход: 500000 + Когда Расчитать год + То Есть цель: УСН за этот квартал: 20000 + + Примеры: + | квартал | + | 1 | + | 2 | + | 3 | + | 4 | diff --git a/pkg/schet/helpers.go b/pkg/schet/helpers.go new file mode 100644 index 0000000..24ec99c --- /dev/null +++ b/pkg/schet/helpers.go @@ -0,0 +1,11 @@ +package schet + +import ( + "my/gnocount/pkg/accuracy" +) + +func процентСуммы(сумма float64) float64 { + часть := сумма / 100. + часть = float64(accuracy.ОкруглитьРубли(часть)) + return часть +} diff --git a/pkg/schet/init_test.go b/pkg/schet/init_test.go new file mode 100644 index 0000000..d52555d --- /dev/null +++ b/pkg/schet/init_test.go @@ -0,0 +1,61 @@ +package schet + +import ( + "context" + "os" + "testing" + + . "my/gnocount/pkg/testlib" + + "github.com/cucumber/godog" + "github.com/cucumber/godog/colors" + + . "github.com/onsi/gomega" +) + +func InitializeScenario(ctx *godog.ScenarioContext) { + ctx.Step(`^Год: (\d+)$`, год) + ctx.Step(`^Квартал: (\d+)$`, квартал) + ctx.Step(`^Доход: (\d+)$`, доход) + ctx.Step(`^Доход (\d+) за (\d+) квартал$`, доходЗаКвартал) + ctx.Step(`^Расчитать год$`, расчитатьГод) + ctx.Step(`^Есть цель: ОПС за этот квартал: (\d+)$`, естьЦельОПСЗаЭтотКвартал) + ctx.Step(`^Есть цель: УСН за этот квартал: (\d+)$`, естьЦельУСНЗаЭтотКвартал) + ctx.Step(`^Есть цель: (\d+)% сверх (\d+)тр за квартал: "([^"]*)"$`, естьЦельСверхТрЗаКвартал) + ctx.Step(`^Есть цель: (\d+)% сверх (\d+)тр за (\d+) квартал: "([^"]*)"$`, естьЦельСверхТрЗаNКвартал) + ctx.Step(`^Есть цель: (\d+)% сверх (\d+)тр за год: "([^"]*)"$`, естьЦельСверхТрЗаГод) + + // ----------------------- + ctx.Before(func(ctx context.Context, sc *godog.Scenario) (context.Context, error) { + beforeScenario() + return ctx, nil + }) + ctx.After(func(ctx context.Context, sc *godog.Scenario, err error) (context.Context, error) { + afterScenario() + return ctx, nil + }) + InitializeGomegaForGodog(ctx) + _ = Ω +} + +func InitializeSuite(tsc *godog.TestSuiteContext) { + tsc.BeforeSuite(beforeSuite) + tsc.AfterSuite(afterSuite) +} + +func TestMain(t *testing.T) { + var opts = godog.Options{ + Output: colors.Colored(os.Stdout), + Strict: true, + StopOnFailure: true, + TestingT: t, + } + + godog.BindCommandLineFlags("godog.", &opts) + godog.TestSuite{ + Name: "app", + TestSuiteInitializer: InitializeSuite, + ScenarioInitializer: InitializeScenario, + Options: &opts, + }.Run() +} diff --git a/pkg/schet/kvartal.go b/pkg/schet/kvartal.go new file mode 100644 index 0000000..30da805 --- /dev/null +++ b/pkg/schet/kvartal.go @@ -0,0 +1,49 @@ +package schet + +import ( + "errors" +) + +type Квартал struct { + номер int + год *Год + доход float64 + ОПС *ОПС_type + УСН *УСН_type +} + +func NewКвартал(номер int, год *Год) *Квартал { + k := &Квартал{ + номер: номер, + год: год, + } + k.создатьПлатежи() + return k +} + +func (k *Квартал) создатьПлатежи() error { + k.ОПС = NewОПС_type(k) + k.УСН = NewУСН_type(k) + return nil +} + +func (k *Квартал) Номер() int { + return k.номер +} + +func (k *Квартал) ДобавитьДоход(доход float64) error { + k.доход = доход + return nil +} +func (k *Квартал) Доход() float64 { + return k.доход +} + +func (k *Квартал) ПроцентСверх300тр() (float64, error) { + сумма, err := k.год.Сверх300трвКвартале(k.номер) + if err != nil { + return 0, errors.Join(errors.New("Квартал"), errors.New("Сверх300тр"), err) + } + + return процентСуммы(сумма), nil +} diff --git a/pkg/schet/ops.go b/pkg/schet/ops.go new file mode 100644 index 0000000..71b746b --- /dev/null +++ b/pkg/schet/ops.go @@ -0,0 +1,18 @@ +package schet + +type ОПС_type struct { + квартал *Квартал + сумма float64 +} + +func NewОПС_type(квартал *Квартал) *ОПС_type { + o := &ОПС_type{ + квартал: квартал, + сумма: 12375, + } + return o +} + +func (o *ОПС_type) Сумма() float64 { + return o.сумма +} diff --git a/pkg/schet/out.go b/pkg/schet/out.go new file mode 100644 index 0000000..c74783e --- /dev/null +++ b/pkg/schet/out.go @@ -0,0 +1,5 @@ +package schet + +type OutIface interface { + Печать(*Год) error +} diff --git a/pkg/schet/schet.go b/pkg/schet/schet.go new file mode 100644 index 0000000..1fd9293 --- /dev/null +++ b/pkg/schet/schet.go @@ -0,0 +1,77 @@ +package schet + +const ( + КоличествоКварталов = 4 + НомерПервогоКвартала = 1 + НомерПоследнегоКвартала = 4 +) + +type Год struct { + год int + цели *Цели + доход float64 + out OutIface +} + +func NewГод(год int) *Год { + g := &Год{ + год: год, + } + g.создатьЦели() + return g +} + +func (g *Год) создатьЦели() { + c := NewЦели(g) + for i := 0; i < КоличествоКварталов; i++ { + c.Кварталы = append(c.Кварталы, NewКвартал(i+1, g)) + } + g.цели = c +} +func (g *Год) Цели() *Цели { + return g.цели +} + +func (g *Год) Год() int { + return g.год +} + +func (g *Год) Квартал(in int) (k *Квартал, e error) { + return g.цели.Квартал(in) +} + +func (g *Год) ДобавитьДоход(доход float64, i int) error { + k, err := g.Квартал(i) + if err != nil { + return err + } + + g.доход += доход + + return k.ДобавитьДоход(доход) +} +func (g *Год) Доход() float64 { + return g.доход +} + +func (g *Год) ПроцентСверх300тр() (float64, error) { + return ПроцентСверх300тр(g.доход), nil +} + +func (g *Год) Сверх300трвКвартале(квартал int) (float64, error) { + сумматор := NewСумматор300тр() + for i := НомерПервогоКвартала; i <= квартал; i++ { + k, err := g.Квартал(i) + if err != nil { + return 0, err + } + сумматор.ДобавитьКвартал(k.доход) + } + + return сумматор.Квартал(квартал) +} + +func (g *Год) Вывести(out OutIface) error { + g.out = out + return out.Печать(g) +} diff --git a/pkg/schet/schet_test.go b/pkg/schet/schet_test.go new file mode 100644 index 0000000..8469222 --- /dev/null +++ b/pkg/schet/schet_test.go @@ -0,0 +1,84 @@ +package schet + +import ( + "fmt" + . "my/gnocount/pkg/testlib" + + . "github.com/onsi/gomega" +) + +type testData struct { + g *Год + год_номер int + квартал_номер int + квартал *Квартал + доход float64 + цели *Цели +} + +var ( + t *testData +) + +func resetTestData() { + t = &testData{} +} + +func beforeSuite() { +} +func afterSuite() { +} + +func beforeScenario() { + resetTestData() + _ = Ω + +} +func afterScenario() { +} + +// ----------------------- +func год(год int) { + t.год_номер = год + t.g = NewГод(t.год_номер) + t.цели = t.g.Цели() +} +func квартал(квартал int) { + t.квартал_номер = квартал + k, err := t.цели.Квартал(t.квартал_номер) + Ok(err) + t.квартал = k +} + +func доход(доход float64) { + t.доход = доход + err := t.g.ДобавитьДоход(t.доход, t.квартал_номер) + Ok(err) +} +func доходЗаКвартал(доход float64, квартал int) { + err := t.g.ДобавитьДоход(доход, квартал) + Ok(err) +} + +func расчитатьГод() {} + +func естьЦельОПСЗаЭтотКвартал(v float64) { + Ω(t.квартал.ОПС.Сумма()).To(Be(v), "ОПС за квартал") +} + +func естьЦельУСНЗаЭтотКвартал(v float64) { + Ω(t.квартал.УСН.Сумма()).To(Be(v), "УСН за квартал") +} + +func естьЦельСверхТрЗаКвартал(_, _, оплатить string) { + Ω(t.квартал.ПроцентСверх300тр()).To(Be(Atof(оплатить)), "1пр сверх 300тр за квартал") +} +func естьЦельСверхТрЗаNКвартал(arg1, arg2, in int, оплатить string) { + k, err := t.цели.Квартал(in) + Ok(err) + + Ω(k.ПроцентСверх300тр()).To(Be(Atof(оплатить)), fmt.Sprintf("1пр сверх 300тр за квартал %v", in)) +} +func естьЦельСверхТрЗаГод(_, _, оплатить string) { + Ω(t.g.ПроцентСверх300тр()).To(Be(Atof(оплатить)), "1пр сверх 300тр за год") +} diff --git a/pkg/schet/summator300tr.go b/pkg/schet/summator300tr.go new file mode 100644 index 0000000..550fa85 --- /dev/null +++ b/pkg/schet/summator300tr.go @@ -0,0 +1,53 @@ +package schet + +import "errors" + +const ( + Сумма300тр = 300000 +) + +type Сумматор300тр struct { + набегающим_итогом float64 + сверхСуммы []float64 +} + +func NewСумматор300тр() *Сумматор300тр { + return &Сумматор300тр{} +} + +func (s *Сумматор300тр) Квартал(номер int) (float64, error) { + index := номер - 1 + if index >= len(s.сверхСуммы) || index < 0 { + return 0, errors.New("неизвестный квартал") + } + return s.сверхСуммы[index], nil +} + +func (s *Сумматор300тр) ДобавитьКвартал(сумма float64) { + сверх := s.сверх300трСуммаЗаКвартал(сумма) + s.сверхСуммы = append(s.сверхСуммы, сверх) +} + +func (s *Сумматор300тр) сверх300трСуммаЗаКвартал(сумма_за_квартал float64) float64 { + сумма_предыдущих_кварталов := s.набегающим_итогом + s.набегающим_итогом += сумма_за_квартал + + if s.набегающим_итогом <= Сумма300тр { + return 0 + } + + if сумма_предыдущих_кварталов > Сумма300тр { + return сумма_за_квартал + } + + return s.набегающим_итогом - Сумма300тр +} + +func ПроцентСверх300тр(сумма float64) float64 { + свыше_300тр := сумма - Сумма300тр + if свыше_300тр < 0 { + свыше_300тр = 0 + } + часть := процентСуммы(свыше_300тр) + return часть +} diff --git a/pkg/schet/ucn.go b/pkg/schet/ucn.go new file mode 100644 index 0000000..e92656f --- /dev/null +++ b/pkg/schet/ucn.go @@ -0,0 +1,18 @@ +package schet + +type УСН_type struct { + квартал *Квартал +} + +func NewУСН_type(квартал *Квартал) *УСН_type { + o := &УСН_type{ + квартал: квартал, + } + return o +} + +func (o *УСН_type) Сумма() float64 { + d := o.квартал.Доход() + procent := d / 100. + return 4 * procent +}