Перейти к содержимому

Редактор строк

Эта страница переведена с английского. Читать страницу на английском

Поле Vec<M> модели это список строк, например строки счёта. .lines(M::f, ...) редактирует их как небольшую таблицу внутри формы: добавление, удаление и перемещение строк, переход между ячейками с клавиатуры и итоги, которые обновляются по мере ввода. Вся форма, включая строки, проверяется и сохраняется одним действием (action).

#[model]
pub struct Line {
    #[rule(required, max_len = 80)]
    pub item: String,
    #[rule(min = 1, max = 999)]
    pub quantity: i64,
    #[rule(min = 0)]
    pub unit_price: Money,
}

#[model]
pub struct Invoice {
    #[rule(required, max_len = 80)]
    pub customer: String,
    #[rule(required)]
    pub lines: Vec<Line>,
}

Form::of(invoice)
    .field(Invoice::customer)
    .lines(Invoice::lines, |l| {
        l.column(Line::item)
            .column(Line::quantity)
            .column(Line::unit_price)
            .total(Line::quantity, Line::unit_price)
    })
    .submit(t!("docs.live.save"), save_invoice)

Lines

Строка #ItemQuantityUnit priceИтогоДействия
11 004,28
2968,28
Итого1 972,56

Колонки и итоги

.column(Line::f) добавляет редактируемую колонку с элементом управления, подходящим её типу. .total(quantity, price) показывает для каждой строки количество, умноженное на цену, а под строками сумму, в валюте формы.

Проверка

Каждая строка проверяется правилами своей модели, а ошибки показываются в ячейке. #[rule(required)] на поле Vec означает как минимум одну строку. Число строк ограничивает сервер (MAX_LINES), что бы ни прислал клиент.

Сохранение

Действие принимает Valid<Invoice>, поэтому каждая строка проходит свои правила до запуска действия:

#[action(permission = "sales.invoice.write", audit)]
pub async fn save_invoice(invoice: Valid<Invoice>) -> Result<Money> {
    Ok(Money::tl(invoice.lines.iter().map(|l| l.unit_price.minor * l.quantity).sum()))
}