14.01.2011, 13:44 | #101 |
Участник
|
К сожалению, код пишется разными командами, в разных странах и условиях.
К примеру, команды в Редмонде все больше и больше полагаются на вендоров, теперь уже и при написании кода приложения. При этом уровень code review в таких командах обычно тоже намного ниже, чем хотелось бы. То есть даже если в FTE там наняты хорошие сотрудники (хотя я уже высказывался по этому поводу в какой-то другой теме - мы не нанимаем людей со знанием АХ), то качество вендоров Вы врядли сможете себе даже представить. Раз уж дискуссия идет в этой теме, приведу еще пример кода, тоже от вендоров. Код взят с одной из форм в АХ6. Приведу весь код метода, просто чтобы можно было оценить всю мощь гения: X++: public void setUnitOfMeasureState() { UnitOfMeasure tblUnitOfMeasure; if (ecoResDomain.DataType == AttributeDataType::Integer || ecoResDomain.DataType == AttributeDataType::Decimal) { // Enable unit of measure group if (!unitOfMeasureGroup.enabled()) { unitOfMeasureGroup.enabled(true); } if (ecoResDomainUnitOfMeasure.RecId && ecoResBoundedDomainValue.RecId) { // Enable bounded unit of measure combo boxes if (!intUnitOfMeasureComboBox.visible()) { intUnitOfMeasureComboBox.visible(true); } // Populate the integer bounded unit of measure combo box intUnitOfMeasureComboBox.clear(); while select Symbol from tblUnitOfMeasure where tblUnitOfMeasure.UnitOfMeasureClass == ecoResDomainUnitOfMeasure.UnitOfMeasureClass { intUnitOfMeasureComboBox.add(tblUnitOfMeasure.Symbol); } if (intUnitOfMeasureComboBox.count() > 0) { intUnitOfMeasureComboBox.selection(0); } if (ecoResValueLower_EcoResIntValue.RecId && ecoResValueLower_EcoResIntValue.IntUnitOfMeasure) { // Set the unit of measure selection tblUnitOfMeasure = UnitOfMeasure::find(ecoResValueLower_EcoResIntValue.IntUnitOfMeasure); intUnitOfMeasureComboBox.selectText(tblUnitOfMeasure.Symbol); } else if (ecoResDomainUnitOfMeasure.DefaultUnitOfMeasure) { // Set the unit of measure selection tblUnitOfMeasure = UnitOfMeasure::find(ecoResDomainUnitOfMeasure.DefaultUnitOfMeasure); intUnitOfMeasureComboBox.selectText(tblUnitOfMeasure.Symbol); // Set the unit of measure foreign keys if (ecoResValueLower_EcoResIntValue.RecId) { ecoResValueLower_EcoResIntValue.IntUnitOfMeasure = tblUnitOfMeasure.RecId; } if (ecoResValueUpper_EcoResIntValue.RecId) { ecoResValueUpper_EcoResIntValue.IntUnitOfMeasure = tblUnitOfMeasure.RecId; } } else if (intUnitOfMeasureComboBox.count() > 0) { // Set the unit of measure foreign keys if (ecoResValueLower_EcoResIntValue.RecId) { ecoResValueLower_EcoResIntValue.IntUnitOfMeasure = UnitOfMeasure::findBySymbol(intUnitOfMeasureComboBox.getText(intUnitOfMeasureComboBox.selection())).RecId; } if (ecoResValueUpper_EcoResIntValue.RecId) { ecoResValueUpper_EcoResIntValue.IntUnitOfMeasure = UnitOfMeasure::findBySymbol(intUnitOfMeasureComboBox.getText(intUnitOfMeasureComboBox.selection())).RecId; } } if (!floatUnitOfMeasureComboBox.visible()) { floatUnitOfMeasureComboBox.visible(true); } // Populate the float unit of measure combo box floatUnitOfMeasureComboBox.clear(); while select Symbol from tblUnitOfMeasure where tblUnitOfMeasure.UnitOfMeasureClass == ecoResDomainUnitOfMeasure.UnitOfMeasureClass { floatUnitOfMeasureComboBox.add(tblUnitOfMeasure.Symbol); } if (floatUnitOfMeasureComboBox.count() > 0) { floatUnitOfMeasureComboBox.selection(0); } if (ecoResValueLower_EcoResFloatValue.RecId && ecoResValueLower_EcoResFloatValue.FloatUnitOfMeasure) { // Set the unit of measure selection tblUnitOfMeasure = UnitOfMeasure::find(ecoResValueLower_EcoResFloatValue.FloatUnitOfMeasure); floatUnitOfMeasureComboBox.selectText(tblUnitOfMeasure.Symbol); } else if (ecoResDomainUnitOfMeasure.DefaultUnitOfMeasure) { // Set the unit of measure selection tblUnitOfMeasure = UnitOfMeasure::find(ecoResDomainUnitOfMeasure.DefaultUnitOfMeasure); floatUnitOfMeasureComboBox.selectText(tblUnitOfMeasure.Symbol); // Set the unit of measure foreign keys if (ecoResValueLower_EcoResFloatValue.RecId) { ecoResValueLower_EcoResFloatValue.FloatUnitOfMeasure = tblUnitOfMeasure.RecId; } if (ecoResValueUpper_EcoResFloatValue.RecId) { ecoResValueUpper_EcoResFloatValue.FloatUnitOfMeasure = tblUnitOfMeasure.RecId; } } else if (floatUnitOfMeasureComboBox.count() > 0) { // Set the unit of measure foreign keys if (ecoResValueLower_EcoResFloatValue.RecId) { ecoResValueLower_EcoResFloatValue.FloatUnitOfMeasure = UnitOfMeasure::findBySymbol(floatUnitOfMeasureComboBox.getText(floatUnitOfMeasureComboBox.selection())).RecId; } if (ecoResValueUpper_EcoResIntValue.RecId) { ecoResValueUpper_EcoResFloatValue.FloatUnitOfMeasure = UnitOfMeasure::findBySymbol(floatUnitOfMeasureComboBox.getText(floatUnitOfMeasureComboBox.selection())).RecId; } } } else { // Disable unit of measure combo boxes if (intUnitOfMeasureComboBox.visible()) { intUnitOfMeasureComboBox.visible(false); } if (floatUnitOfMeasureComboBox.visible()) { floatUnitOfMeasureComboBox.visible(false); } } } else { // Disable unit of measure group if (unitOfMeasureGroup.enabled()) { unitOfMeasureGroup.enabled(false); } // Disable unit of measure combo boxes if (intUnitOfMeasureComboBox.visible()) { intUnitOfMeasureComboBox.visible(false); } if (floatUnitOfMeasureComboBox.visible()) { floatUnitOfMeasureComboBox.visible(false); } } } |
|
14.01.2011, 13:47 | #102 |
Участник
|
Цитата:
Необходимо это или нет - это уже другой вопрос. А если это таким было ТЗ, тогда чего на кодера пенять? Это может быть баг, но это не wtf |
|
14.01.2011, 13:58 | #103 |
Модератор
|
Цитата:
P.S. а может у автора этот код никакого дискомфорта не вызывает - у них вообще похоже свое, особенное чувство прекрасного
__________________
-ТСЯ или -ТЬСЯ ? |
|
|
За это сообщение автора поблагодарили: S.Kuskov (1). |
14.01.2011, 14:32 | #104 |
----------------
|
как правильно заметил TasmanianDevil основная идея - "закрыть на редактирование 7 полей независимо от других", а вот открытие всех остальных полей - явная "фича" метода, с которой придется бороться, если вам понадобится закрыть "свои" поля при других условиях.
|
|
14.01.2011, 14:52 | #105 |
Мрачный тип
|
2S.Kuskov
Тут даже гадать не надо, какое ТЗ - в методе объем тупизны измеряется возом и маленькой тележкой. У LedgerJournalTrans в репозитарии всего чуть менее 20 полей с запретом редактирования - для них этот метод не будет работать, ибо запрет на репозитарии приоритетнее. Для остальных полей редактирование в репозитарии разрешено. На источнике данных на форме ни одно из полей не имеет запрета на редактирование. Часть полей закрыто на редактирование на контролах. Все итерации по перебору полей, кроме этих семи, и выставление им свойства на разрешение редактирования будут либо повторять выставление уже имеющихся свойств, либо работать впустую - т.е. по сути будут абсолютно бесполезны. LedgerJournalTrans - очень тяжелая таблица, полей в ней очень много (в нашей конфигурации - почти 200) и они перебираются все. Дополнительный тормоз на active() в виде такой кучи бесполезных итераций никуда и никому не уперся, IMHO 2Wamr Именно в ходе своей доработки с закрытием (которое не работало) собственных полей и нарыл сию прелесть
__________________
Мы летаем, кружимся, нагоняем ужасы ... |
|
14.01.2011, 15:15 | #106 |
Участник
|
Претензии понял, негодование разделяю. Но ИМХО Индус не специально
|
|
19.01.2012, 21:10 | #107 |
Участник
|
Индийский код или я чего-то не понимаю ?
\Classes\DirUtility\getPartyCompanyList X++: static container getPartyCompanyList() { DirPartyTable partyTable; container dataAreaIdList; container ret; int i; container virtualCompanyList = DirUtility::getVirtualDataAreaList(); ; if (confind(virtualCompanyList,partyTable.DataAreaId)) { dataAreaIdList= conpeek(virtualCompanyList,confind(virtualCompanyList,partyTable.DataAreaId)+1); for (i=1 ; i<=conlen(dataAreaIdList) ; i++) { ret = conins(ret,i,conpeek(dataAreaIdList,i)); } return ret; } return [partyTable.DataAreaId]; } X++: for (i=1 ; i<=conlen(dataAreaIdList) ; i++) { ret = conins(ret,i,conpeek(dataAreaIdList,i)); } return ret; X++: return dataAreaIdList Последний раз редактировалось Logger; 19.01.2012 в 21:15. |
|
|
За это сообщение автора поблагодарили: gl00mie (3). |
23.01.2012, 12:44 | #108 |
Мрачный тип
|
Bug ! Жирный bug ! Кому свежую тушку жирного bug'а ?
DAX2009, ядро 5.0.1000.52
Объявляем EDT на основе int64 с любым ArraySize, бОльшим 1, и именем MyType. Создаем элементарный класс X++: class TestClass
{
MyType x;
} X++: MyType parmX(MyType _x = x) { if(x != _x) x = _x; return x; }
__________________
Мы летаем, кружимся, нагоняем ужасы ... |
|
|
За это сообщение автора поблагодарили: Logger (3), lev (5), S.Kuskov (5). |
23.01.2012, 12:55 | #109 |
Участник
|
Где-то видел обертку в виде темповой таблички для типа Dimension. Табличка состояла из одного поля Dimension и была очевидно нужна для корректного хранения и передачи индексной переменной.
Может вам что-то подобное сделать, пока ядро не пофиксили ? |
|
28.04.2012, 09:25 | #110 |
Участник
|
|
|
|
За это сообщение автора поблагодарили: S.Kuskov (1). |
28.04.2012, 14:15 | #111 |
NavAx
|
Цитата:
Сообщение от EVGL
Шокированный коллега прислал сегодня сей изысканный образец творчества местного программиста:
X++: actorForSpoiling = prodTableRun.QtySched / InventTableRun.qtyPerLayer / prodTableRun.MEM_NumOfLanes; numofpage = 1; if (factorForSpoiling > 198) numofpage = 12; else if (factorForSpoiling > 180) numofpage = 11; else if (factorForSpoiling > 162) numofpage = 10; else if (factorForSpoiling > 144) numofpage = 9; else if (factorForSpoiling > 126) numofpage = 8; else if (factorForSpoiling > 108) numofpage = 7; else if (factorForSpoiling > 90) numofpage = 6; else if (factorForSpoiling > 72) numofpage = 5; else if (factorForSpoiling > 54) numofpage = 4; else if (factorForSpoiling > 36) numofpage = 3; else if (factorForSpoiling > 18) numofpage = 2; X++: numofpage = trunc(((factorForSpoiling - 1) / 18) + 1); |
|
28.04.2012, 14:49 | #112 |
Участник
|
|
|
30.05.2012, 09:32 | #113 |
Мрачный тип
|
В продолжении темы о EDT-массиве на основе int64 ...
Имеется: 1) наличие поля с таким EDT в таблице 2) некий коде, обращающийся к значению этого поля по индексу, являющемуся переменной типа MyTable.MyField[i] = X. 3) дебаггер, в котором либо помещаем в Watches это конкретное поле, либо просто наводим на него курсор, чтобы получить tooltip со значением Клиент лег ...
__________________
Мы летаем, кружимся, нагоняем ужасы ... |
|
|
За это сообщение автора поблагодарили: kashperuk (5). |
13.06.2012, 12:18 | #114 |
Участник
|
Цитата:
Сообщение от TasmanianDevil
DAX2009, ядро 5.0.1000.52
Объявляем EDT на основе int64 с любым ArraySize, бОльшим 1, и именем MyType. Создаем элементарный класс X++: class TestClass
{
MyType x;
} X++: MyType parmX(MyType _x = x) { if(x != _x) x = _x; return x; } Попробовал на последней версии, у меня компилируется без проблем. Мой EDT называется правда Type1, но я не думаю, что есть разница. |
|
13.06.2012, 17:44 | #115 |
Участник
|
Верхнюю половину метода написал один человек; нижнюю - другой, не глядя на верхнюю, и - внимание - ловко "оптимизировал" код использовав список полей. BestPractice ошибок нет - все отлично. Это из стандартного кода AX 2012.
CustWriteOff\checkForDuplicateVouchers X++: protected boolean checkForDuplicateVouchers(Voucher _voucher, TransDate _transDate, recId _existingCustTransRecId) { boolean found; VendTrans vendTrans; // check for duplicate customer transaction found = (select firstonly RecId from custTrans where custTrans.Voucher == _voucher && custTrans.TransDate == _transDate && custTrans.RecId != _existingCustTransRecId).RecId != 0; if (found == true) { return true; } // check for duplicate vendor transactions select count(RecId) from vendTrans where vendTrans.Voucher == _voucher && vendTrans.TransDate == _transDate; found = vendTrans.ReasonRefRecId == 0 ? false : true; return found; } |
|
|
За это сообщение автора поблагодарили: kashperuk (5). |
14.06.2012, 16:43 | #116 |
Участник
|
Napalm, а расскажите подробнее про эту находку.
Где и как столкнулись? Я посмотрел, и этот код там существовал в таком виде с декабря 2008 года. Раз до этого не заметили (а я проверил - не заметили), то скорее всего никто из кастомеров с этим не сталкивался |
|
14.06.2012, 19:04 | #117 |
Участник
|
Цитата:
Скорее всего проблемы будут если этот код "починить". Какой смысл искать дубликаты в VendTrans по полю Voucher, используя значение Voucher из CustTrans? Возможно будут ложные срабатывания - зависит от настройки номерных серий. |
|
10.09.2012, 11:42 | #118 |
Moderator
|
В последнем DAX2009RU8 наткнулся на замечательный кусочек кода в reqTrans.findCommon():
X++: if (reqTrans.RefType == ReqRefType::TransferDemand) { select firstonly reqTrans index hint RefIdx where reqTrans.ReqPlanId == reqTrans.ReqPlanId && reqTrans.RefType == ReqRefType::TransferPlannedOrder && reqTrans.RefId == reqTrans.RefId; } Можно починить примерно вот так: X++: reqTransCaller=reqTrans; select firstonly reqTrans index hint RefIdx where reqTrans.ReqPlanId == reqTransCaller.ReqPlanId && reqTrans.RefType == ReqRefType::TransferPlannedOrder && reqTrans.RefId == reqTransCaller.RefId; |
|
|
За это сообщение автора поблагодарили: mazzy (2), abv2703 (1), gl00mie (5), madm (1). |
11.09.2012, 10:23 | #119 |
NavAx
|
Банковские чеки
Столкнулся с совершенно удивительным и поразительным функционалом банковских чеков. В них применена уникальная технология формирования строк отчета. Это просто много-строчная текстовая переменная, которую запихивают в контрол отчета. Расстояние между колонками и набор доступных полей захардкожены. Причем в десятках мест одновременно:
\Classes\BankChequeCopy\fillSlipText \Classes\CustVendCheque\fillSlipTxt \Classes\CustVendCheque\fillSlipTxtHF \Classes\BankPrintTestCheque\createTestCheque Самое веселое, что этот хардкод одинаков для всех возможных форматов. И перемешан с логикой. Так что если в вашей стране или банке принято использовать другой набор колонок или просто зазор между ними, придется изрядно кодить. Если нужно поддерживать несколько форматов в холдинге, кодить приходится в несколько раз больше. Что характерно, сей код используется, как минимум, с версии 4.0. Создается впечатление, что это какая-то запатентованная методика создания отчетов, которой дорожат, а потому бережно переносят из версии в версию.
__________________
Isn't it nice when things just work? |
|
|
За это сообщение автора поблагодарили: gl00mie (2). |
24.09.2012, 09:58 | #120 |
Мрачный тип
|
Глюк в drag-n-drop edit-методов
DAX2009, kernel/application 5.0.1500.6491
На источнике данных формы N edit-методов, возвращающих значение Enum'а NoYes. Выделяем эти методы и перетаскиваем на дизайн формы - часть контролов создались checkbox'ами, часть создалась radiobutton'ами. Удаление контролов и повтор этого действия дает аналогичную картину, только меняется распределение кому из методов достается checkbox, а кому radiobutton - некая лотерея. Меняем возвращаемый тип для этих методов с закрытого NoYes на открытый NoYesCombo, у которого прямо прописан combobox как стиль контрола для отображения, и повторяем процедуру drag-n-drop'а методов с источника данных формы на ее дизайн - аналогичная картина.
__________________
Мы летаем, кружимся, нагоняем ужасы ... |
|