Заказы покупателя (часть 2)

Продолжение, первую часть читайте здесь.

Создайте новый Android- проект по сгенерированному шаблону (как это сделать уже рассматривалось ранее) .Откройте MainActivity.java и добавьте следующую процедуру:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*
 * Интерактивный выбор варианта и запуск обмена
 */
private void doSelectStartExchange() {
 
    // адаптер для отображения значений перечислений в диалоге выбора
    PresentationAdapter adapter = new PresentationAdapter(this,
            android.R.layout.simple_spinner_dropdown_item,
            ExchangeVariant.values());
 
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setAdapter(adapter, new DialogInterface.OnClickListener() {
 
        @Override
        public void onClick(DialogInterface dialog, int which) {
            ExchangeVariant variant = ExchangeVariant.values()[which];
            startExchange(variant, true);
            dialog.dismiss();
 
        }
    });
    builder.setTitle("Выбор варианта обмена");
    builder.create().show();
 
}
/*
 * Интерактивный выбор варианта и запуск обмена
 */
private void doSelectStartExchange() {

	// адаптер для отображения значений перечислений в диалоге выбора
	PresentationAdapter adapter = new PresentationAdapter(this,
			android.R.layout.simple_spinner_dropdown_item,
			ExchangeVariant.values());

	AlertDialog.Builder builder = new AlertDialog.Builder(this);
	builder.setAdapter(adapter, new DialogInterface.OnClickListener() {

		@Override
		public void onClick(DialogInterface dialog, int which) {
			ExchangeVariant variant = ExchangeVariant.values()[which];
			startExchange(variant, true);
			dialog.dismiss();

		}
	});
	builder.setTitle("Выбор варианта обмена");
	builder.create().show();

}

В методе OnOptionsItemSelected  замените вызов startExchange(ExchangeVariant.FULL, true) на doSelectStartExchange(). Теперь вместо безусловного запуска обмена по варианту «FULL»  будет  использоваться интерактивный выбор.

Запустите приложение на эмуляторе и выполните обмен по варианту «Начальная инициализация».

В процессе обмена создается локальная база данных и заполняется полученными от сервера данными. Давайте посмотрим, где и как эти данных хранятся.

В мобильном приложении на платформе Android для хранения данных используется Sqlite. Файл базы данных один и расположен по стандартному пути:  //data/data/<имя пакета вашего приложения>/datadases/database.db.
Доступ к этому файлу имеет только ваше приложение.  Вы можете скопировать его с эмулятора:

Чтобы получить доступ к этому файлу на Android устройстве вам потребуется «Root-доступ».

Для изучения содержимого можно воспользоваться бесплатным плагином “Sqlite Manager” для Firefox:

Давайте программно создадим новый документ «Заказ покупателя». Добавьте в макет layout\activity_main.xml  кнопку, по нажатию на которую, будет вызвана процедура:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/*
 * Создать новый документ «Заказ покупателя».
 */
protected void createNewOrder() throws SQLException {
 
        //Помощник для работы с базой данных
        DBOpenHelper helper = getHelper();
 
        //Менеджер для работы  константами
        ConstantsDao costDao = helper.getDao(Constants.class);
 
        //Прочитать набор констант
        Constants constants = costDao.read();
        Log.i(TAG, "Основная организация:" + constants.osnovnayaOrganizaciya.getDescription());
        Log.i(TAG, "Основной тип цен продажи: " + constants.osnovnoiTipCenProdazhi.getDescription());
 
        //Найти контрагента по наименованию
        CatalogKontragentiDao kontragentDao = helper.getDao(CatalogKontragenti.class);
        CatalogKontragenti kontragent = kontragentDao.findByDescription("Белявский-частное лицо");
        Log.i(TAG, "Покупатель: " + kontragent.getDescription());
 
        CatalogDogovoriKontragentovDao dogovorDao = helper.getDao(CatalogDogovoriKontragentov.class);
 
        //Параметры отбора  по организации, типу цен и владельцу
        HashMap<String,Object> filter = new HashMap<String, Object>();
        filter.put(CatalogDogovoriKontragentov.FIELD_NAME_ORGANIZACIYA, constants.osnovnayaOrganizaciya);
        filter.put(CatalogDogovoriKontragentov.FIELD_NAME_TIP_CEN, constants.osnovnoiTipCenProdazhi);
        filter.put(CatalogDogovoriKontragentov.FIELD_NAME_OWNER, kontragent);
 
        //Выбрать первый договор контрагента, если есть  или пустая ссылка
        CatalogDogovoriKontragentov dogovor = dogovorDao.emptyRef();
        List<CatalogDogovoriKontragentov> lstDogovors = dogovorDao.select(filter);
        if(lstDogovors.size()>0)
                dogovor = lstDogovors.get(0);
        Log.i(TAG, "Договор: " + dogovor.getDescription());
 
        //найти главный склад по коду
        CatalogSkladiDao skladiDao = helper.getDao(CatalogSkladi.class);
        CatalogSkladi sklad = skladiDao.findByCode("000000001");
        Log.i(TAG, "Cклад: " + sklad.getDescription());
 
        //Ответственного
        CatalogPolzovateliDao polzovateliDao = helper.getDao(CatalogPolzovateli.class);
        CatalogPolzovateli polzovatel = polzovateliDao.findByCode("Иванов И.И.");
        Log.i(TAG, "Пользователь: " + polzovatel.getPresentation());
 
        //Найти валюту по коду
        CatalogValyutiDao valutDao = helper.getDao(CatalogValyuti.class);
        CatalogValyuti valyta = valutDao.findByCode("643");
        Log.i(TAG, "Валюта: " + valyta.getPresentation());
 
        //длина номера документа
        int DOC_NUMBER_LEN = 11;
 
        //Менеджер для работы с документами, другой вариант инициализации
        DocumentZakazPokupatelyaDao docDao = new DocumentZakazPokupatelyaDao(getConnectionSource());
 
        int numerator = docDao.getNextNumber();
        String strNumber = docDao.formatNumber("AND-",numerator, DOC_NUMBER_LEN);
        Log.i(TAG, "Номер нового документа: " + strNumber);
 
        //"Документ объект"
        DocumentZakazPokupatelya doc = docDao.newItem();
 
        doc.setDate(new Date(System.currentTimeMillis()));
        doc.setNumber(strNumber);
        doc.setPosted(false);
 
        //реквизиты шапки
        doc.organizaciya = constants.osnovnayaOrganizaciya;
        doc.kontragent = kontragent;
        doc.dogovorKontragenta = dogovor;
        doc.sklad = sklad;
        doc.kommentarii = "Создан на Android";
        doc.otvetstvennii = polzovatel;
        doc.tipCen = constants.osnovnoiTipCenProdazhi;
        doc.valyutaDokumenta = valyta;
        //отгрузка через 5 дней
        doc.dataOtgruzki = DateHelper.addDays(doc.getDate(), 5);
 
        //Подготовить строки табличной части
        List<DocumentZakazPokupatelyaTPTovari> rows = makeTablePartRows(doc,constants.osnovnoiTipCenProdazhi,
                                new String[] { "Мясорубка ЭКМ-3",
                                                "Чайник BINATONE  AEJ-1001,  2,2л", "Телевизор \"JVC\"" });
 
        //Посчитать сумму документа
        double summa = 0;
        for (DocumentZakazPokupatelyaTPTovari row : rows) {
                summa +=row.summa;
        }
        doc.summa = summa;
 
        //запись данных в локальную базу
        //Сначала должен быть записан сам документ
        docDao.create(doc);
 
        //запись табличной части (вариант через ForeignCollection)
        doc.tovari = docDao.getEmptyForeignCollection("tovari");
        for (DocumentZakazPokupatelyaTPTovari row : rows) {
                //aвтоматическая запись сразу при добавлении
                doc.tovari.add(row);
        }
 
        showToast("Документ добавлен!");
 
}
/*
 * Создать новый документ «Заказ покупателя».
 */
protected void createNewOrder() throws SQLException {

    	//Помощник для работы с базой данных
    	DBOpenHelper helper = getHelper();

    	//Менеджер для работы  константами
    	ConstantsDao costDao = helper.getDao(Constants.class);

    	//Прочитать набор констант
    	Constants constants = costDao.read();
    	Log.i(TAG, "Основная организация:" + constants.osnovnayaOrganizaciya.getDescription());
    	Log.i(TAG, "Основной тип цен продажи: " + constants.osnovnoiTipCenProdazhi.getDescription());

    	//Найти контрагента по наименованию
    	CatalogKontragentiDao kontragentDao = helper.getDao(CatalogKontragenti.class);
    	CatalogKontragenti kontragent = kontragentDao.findByDescription("Белявский-частное лицо");
    	Log.i(TAG, "Покупатель: " + kontragent.getDescription());

    	CatalogDogovoriKontragentovDao dogovorDao = helper.getDao(CatalogDogovoriKontragentov.class);

    	//Параметры отбора  по организации, типу цен и владельцу
    	HashMap<String,Object> filter = new HashMap<String, Object>();
    	filter.put(CatalogDogovoriKontragentov.FIELD_NAME_ORGANIZACIYA, constants.osnovnayaOrganizaciya);
    	filter.put(CatalogDogovoriKontragentov.FIELD_NAME_TIP_CEN, constants.osnovnoiTipCenProdazhi);
    	filter.put(CatalogDogovoriKontragentov.FIELD_NAME_OWNER, kontragent);

    	//Выбрать первый договор контрагента, если есть  или пустая ссылка
    	CatalogDogovoriKontragentov dogovor = dogovorDao.emptyRef();
    	List<CatalogDogovoriKontragentov> lstDogovors = dogovorDao.select(filter);
    	if(lstDogovors.size()>0)
            	dogovor = lstDogovors.get(0);
    	Log.i(TAG, "Договор: " + dogovor.getDescription());

    	//найти главный склад по коду
    	CatalogSkladiDao skladiDao = helper.getDao(CatalogSkladi.class);
    	CatalogSkladi sklad = skladiDao.findByCode("000000001");
    	Log.i(TAG, "Cклад: " + sklad.getDescription());

    	//Ответственного
    	CatalogPolzovateliDao polzovateliDao = helper.getDao(CatalogPolzovateli.class);
    	CatalogPolzovateli polzovatel = polzovateliDao.findByCode("Иванов И.И.");
    	Log.i(TAG, "Пользователь: " + polzovatel.getPresentation());

    	//Найти валюту по коду
    	CatalogValyutiDao valutDao = helper.getDao(CatalogValyuti.class);
    	CatalogValyuti valyta = valutDao.findByCode("643");
    	Log.i(TAG, "Валюта: " + valyta.getPresentation());

    	//длина номера документа
    	int DOC_NUMBER_LEN = 11;

    	//Менеджер для работы с документами, другой вариант инициализации
    	DocumentZakazPokupatelyaDao docDao = new DocumentZakazPokupatelyaDao(getConnectionSource());

    	int numerator = docDao.getNextNumber();
    	String strNumber = docDao.formatNumber("AND-",numerator, DOC_NUMBER_LEN);
    	Log.i(TAG, "Номер нового документа: " + strNumber);

    	//"Документ объект"
    	DocumentZakazPokupatelya doc = docDao.newItem();

    	doc.setDate(new Date(System.currentTimeMillis()));
    	doc.setNumber(strNumber);
    	doc.setPosted(false);

    	//реквизиты шапки
    	doc.organizaciya = constants.osnovnayaOrganizaciya;
    	doc.kontragent = kontragent;
    	doc.dogovorKontragenta = dogovor;
    	doc.sklad = sklad;
    	doc.kommentarii = "Создан на Android";
    	doc.otvetstvennii = polzovatel;
    	doc.tipCen = constants.osnovnoiTipCenProdazhi;
    	doc.valyutaDokumenta = valyta;
    	//отгрузка через 5 дней
    	doc.dataOtgruzki = DateHelper.addDays(doc.getDate(), 5);

    	//Подготовить строки табличной части
    	List<DocumentZakazPokupatelyaTPTovari> rows = makeTablePartRows(doc,constants.osnovnoiTipCenProdazhi,
                            	new String[] { "Мясорубка ЭКМ-3",
                                            	"Чайник BINATONE  AEJ-1001,  2,2л", "Телевизор \"JVC\"" });

    	//Посчитать сумму документа
    	double summa = 0;
    	for (DocumentZakazPokupatelyaTPTovari row : rows) {
            	summa +=row.summa;
    	}
    	doc.summa = summa;

    	//запись данных в локальную базу
    	//Сначала должен быть записан сам документ
    	docDao.create(doc);

    	//запись табличной части (вариант через ForeignCollection)
    	doc.tovari = docDao.getEmptyForeignCollection("tovari");
    	for (DocumentZakazPokupatelyaTPTovari row : rows) {
            	//aвтоматическая запись сразу при добавлении
            	doc.tovari.add(row);
    	}

    	showToast("Документ добавлен!");

}

Добавьте также в MainActivity.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/*
* Ищем номенклатуру по наименованию, получаем цену и добавляем с список
* строк табличной части
*/
private List<DocumentZakazPokupatelyaTPTovari> makeTablePartRows(
                DocumentZakazPokupatelya doc, CatalogTipiCenNomenklaturi tipCen,
                String[] nomenklaturaNames) throws SQLException {
 
        //Подготовить пустой список строк табличной части
        List<DocumentZakazPokupatelyaTPTovari> rows = new ArrayList<DocumentZakazPokupatelyaTPTovari>();
 
        //Менеджеры данных: табличной части документа, справочника «Номенклатура» и внешней таблицы цен
        DocumentZakazPokupatelyaTPTovariDao TPTovariDao = getHelper().getDao(DocumentZakazPokupatelyaTPTovari.class);
        CatalogNomenklaturaDao nomenklaturaDao = getHelper().getDao(CatalogNomenklatura.class);
        ExTableCeniDao ceniDao = getHelper().getDao(ExTableCeni.class);
 
        int lineNumber = 1;
 
        for (String name : nomenklaturaNames) {
 
                CatalogNomenklatura nomenklatura = nomenklaturaDao.findByDescription(name);
                if (!CatalogNomenklatura.isEmpty(nomenklatura)) {
 
                        ExTableCeni priceRow = ceniDao.findPriceRow(tipCen,     nomenklatura);
 
                        if(priceRow!=null){
 
                                //Создать новую строку табличной части
                                DocumentZakazPokupatelyaTPTovari row = TPTovariDao.newItem(doc, lineNumber++);
                                row.nomenklatura = priceRow.nomenklatura;
                                row.harakteristika = priceRow.harakteristikaNomenklaturi;
                                row.edinicaIzmereniya = priceRow.edinicaIzmereniya;
                                row.cena = priceRow.cena;
                                row.kolichestvo = 1;
                                row.summa = row.cena * row.kolichestvo;
 
                                Log.i(TAG, "строка ТЧ: номенклатура = " + row.nomenklatura + ", цена = " + row.cena);
 
                                rows.add(row);
                        }
 
                }
        }
        return rows;
 
}
/*
* Ищем номенклатуру по наименованию, получаем цену и добавляем с список
* строк табличной части
*/
private List<DocumentZakazPokupatelyaTPTovari> makeTablePartRows(
            	DocumentZakazPokupatelya doc, CatalogTipiCenNomenklaturi tipCen,
            	String[] nomenklaturaNames) throws SQLException {

    	//Подготовить пустой список строк табличной части
    	List<DocumentZakazPokupatelyaTPTovari> rows = new ArrayList<DocumentZakazPokupatelyaTPTovari>();

    	//Менеджеры данных: табличной части документа, справочника «Номенклатура» и внешней таблицы цен
    	DocumentZakazPokupatelyaTPTovariDao TPTovariDao = getHelper().getDao(DocumentZakazPokupatelyaTPTovari.class);
    	CatalogNomenklaturaDao nomenklaturaDao = getHelper().getDao(CatalogNomenklatura.class);
    	ExTableCeniDao ceniDao = getHelper().getDao(ExTableCeni.class);

    	int lineNumber = 1;

    	for (String name : nomenklaturaNames) {

            	CatalogNomenklatura nomenklatura = nomenklaturaDao.findByDescription(name);
            	if (!CatalogNomenklatura.isEmpty(nomenklatura)) {

                    	ExTableCeni priceRow = ceniDao.findPriceRow(tipCen, 	nomenklatura);

                    	if(priceRow!=null){

                            	//Создать новую строку табличной части
                            	DocumentZakazPokupatelyaTPTovari row = TPTovariDao.newItem(doc, lineNumber++);
                            	row.nomenklatura = priceRow.nomenklatura;
                            	row.harakteristika = priceRow.harakteristikaNomenklaturi;
                            	row.edinicaIzmereniya = priceRow.edinicaIzmereniya;
                            	row.cena = priceRow.cena;
                            	row.kolichestvo = 1;
                            	row.summa = row.cena * row.kolichestvo;

                            	Log.i(TAG, "строка ТЧ: номенклатура = " + row.nomenklatura + ", цена = " + row.cena);

                            	rows.add(row);
                    	}

            	}
    	}
    	return rows;

}

В модуль ExTableCeniDao.java функцию поиска цены:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* Получить запись из таблицы цен (без учета характеристики)
*
* @param tipCen
*           тип цен
* @param nomenklatura
*           номеклатура
* @return
* @throws SQLException
*/
public ExTableCeni findPriceRow(CatalogTipiCenNomenklaturi tipCen,
                CatalogNomenklatura nomenklatura) throws SQLException {
        ExTableCeni priceRow = null;
 
        HashMap<String, Object> filter = new HashMap<String, Object>();
        filter.put(ExTableCeni.FIELD_NAME_TIP_CEN, tipCen);
        filter.put(ExTableCeni.FIELD_NAME_NOMENKLATURA, nomenklatura);
 
        List<ExTableCeni> lst = select(filter);
        if (lst.size() > 0)
                priceRow = lst.get(0);
 
        return priceRow;
}
/**
* Получить запись из таблицы цен (без учета характеристики)
*
* @param tipCen
*        	тип цен
* @param nomenklatura
*        	номеклатура
* @return
* @throws SQLException
*/
public ExTableCeni findPriceRow(CatalogTipiCenNomenklaturi tipCen,
            	CatalogNomenklatura nomenklatura) throws SQLException {
    	ExTableCeni priceRow = null;

    	HashMap<String, Object> filter = new HashMap<String, Object>();
    	filter.put(ExTableCeni.FIELD_NAME_TIP_CEN, tipCen);
    	filter.put(ExTableCeni.FIELD_NAME_NOMENKLATURA, nomenklatura);

    	List<ExTableCeni> lst = select(filter);
    	if (lst.size() > 0)
            	priceRow = lst.get(0);

    	return priceRow;
}

Кода много, но на самом деле ничего сложно в нем нет. Логически он похож на код 1С: найти элементы справочника и присвоить реквизитам создаваемого документа. Всплывающие подсказки есть практически ко всем методам и русифицированы на 95%.

Важные замечания:

  • в текущей версии FBA нет информации о необходимой длине номера документов и справочников, вы должны позаботиться об этом самостоятельно. Чтобы обеспечить контроль уникальности номеров вы можете использовать префикс.
  • Так как для табличных частей включена «поддержка внешних ключей» (Foreign Key), необходимо сначала сохранить сам документ, прежде чем добавить запись в таблицу табличной части;
  • Запись табличной части через getEmptyForeignCollection и вызов метода add() не единственный, может использоваться и общий вариант добавления объектов:

Объект объект = ОбъектDao.newItem();
ОбъектDao.create(объект);

Т.е:

DocumentZakazPokupatelyaTPTovari row = TPTovariDao.newItem(doc, lineNumber);
//заполнить реквизиты табличной части
//row.nomenklatura = priceRow.nomenklatura;
//...
//записать в базу
TPTovariDao.create(row);

Запустите приложение на эмуляторе и создайте заказ. Если вы нигде не ошиблись, будет создан новый документ и выведено выплывающее сообщение.  Посмотрите вывод лога:

Выполните обмен с информационной базой по варианту «Только сохранение данных» или «Полный». В 1С вы увидите созданный вами заказ:

Документ успешно передан в 1С, все реквизиты заполнены.

В этой части мы рассмотрели как программно управлять данными (поиск,  создание и изменение объектов). В следующей части рассмотрим элементы UI облегчающие создание/изменение объектов интерактивно пользователем. Продолжение следует.

Полный код вы можете скачать по адресу https://xp-dev.com/svn/fba_toolkit_public/samples/fbaSample3Order

Дополнительная информация по теме:

OrmLite -  FBA использует эту библиотеку объектно-реляционного отображения данных
Урок 63. Диалоги. AlertDialog. Список с одиночным выбором

Похожие записи: