Начало: модуль счёта добавлен
Этот коммит содержится в:
коммит
5ea7f5d13c
11 изменённых файлов: 488 добавлений и 0 удалений
30
pkg/schet/celi.go
Обычный файл
30
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
|
||||||
|
}
|
82
pkg/schet/features/app.feature
Обычный файл
82
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 |
|
11
pkg/schet/helpers.go
Обычный файл
11
pkg/schet/helpers.go
Обычный файл
|
@ -0,0 +1,11 @@
|
||||||
|
package schet
|
||||||
|
|
||||||
|
import (
|
||||||
|
"my/gnocount/pkg/accuracy"
|
||||||
|
)
|
||||||
|
|
||||||
|
func процентСуммы(сумма float64) float64 {
|
||||||
|
часть := сумма / 100.
|
||||||
|
часть = float64(accuracy.ОкруглитьРубли(часть))
|
||||||
|
return часть
|
||||||
|
}
|
61
pkg/schet/init_test.go
Обычный файл
61
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()
|
||||||
|
}
|
49
pkg/schet/kvartal.go
Обычный файл
49
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
|
||||||
|
}
|
18
pkg/schet/ops.go
Обычный файл
18
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.сумма
|
||||||
|
}
|
5
pkg/schet/out.go
Обычный файл
5
pkg/schet/out.go
Обычный файл
|
@ -0,0 +1,5 @@
|
||||||
|
package schet
|
||||||
|
|
||||||
|
type OutIface interface {
|
||||||
|
Печать(*Год) error
|
||||||
|
}
|
77
pkg/schet/schet.go
Обычный файл
77
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)
|
||||||
|
}
|
84
pkg/schet/schet_test.go
Обычный файл
84
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тр за год")
|
||||||
|
}
|
53
pkg/schet/summator300tr.go
Обычный файл
53
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 часть
|
||||||
|
}
|
18
pkg/schet/ucn.go
Обычный файл
18
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
|
||||||
|
}
|
Загрузка…
Создание таблицы
Сослаться в новой задаче