<span>package com.onresolve.jira.groovy.jql</span><br><br><span>import com.atlassian.jira.component.ComponentAccessor</span><br><span>import com.atlassian.jira.jql.parser.JqlQueryParser</span><br><span>import com.atlassian.jira.jql.query.LuceneQueryBuilder</span><br><span>import com.atlassian.jira.jql.query.QueryCreationContext</span><br><span>import com.atlassian.jira.jql.validator.NumberOfArgumentsValidator</span><br><span>import com.atlassian.jira.user.ApplicationUser</span><br><span>import com.atlassian.jira.util.MessageSet</span><br><span>import com.atlassian.query.clause.TerminalClause</span><br><span>import com.atlassian.query.operand.FunctionOperand</span><br><span>import org.apache.lucene.search.Query</span><br><br><span>import java.time.LocalDate</span><br><br><span>class CreatedQuarter extends AbstractScriptedJqlFunction implements JqlQueryFunction {</span><br><br><span> JqlQueryParser queryParser = ComponentAccessor.getComponent(JqlQueryParser)</span><br><span> LuceneQueryBuilder luceneQueryBuilder = ComponentAccessor.getComponent(LuceneQueryBuilder)</span><br><br><span> @Override</span><br><span> String getDescription() {</span><br><span> "Returns issues created in the selected quarter of the current year. Example: issueFunction in createdQuarter(1)"</span><br><span> }</span><br><br><span> @Override</span><br><span> List<Map> getArguments() {</span><br><span> [</span><br><span> [</span><br><span> description: "Quarter number: 1, 2, 3, or 4",</span><br><span> optional : false,</span><br><span> ]</span><br><span> ]</span><br><span> }</span><br><br><span> @Override</span><br><span> String getFunctionName() {</span><br><span> "createdQuarter"</span><br><span> }</span><br><br><span> @Override</span><br><span> MessageSet validate(ApplicationUser user, FunctionOperand operand, TerminalClause terminalClause) {</span><br><span> def messageSet = new NumberOfArgumentsValidator(1, 1, getI18n()).validate(operand)</span><br><br><span> if (messageSet.hasAnyErrors()) {</span><br><span> return messageSet</span><br><span> }</span><br><br><span> def quarterText = operand.args.first()</span><br><br><span> if (!(quarterText ==~ /[1-4]/)) {</span><br><span> messageSet.addErrorMessage(</span><br><span> "createdQuarter() accepts only 1, 2, 3, or 4. Example: issueFunction in createdQuarter(1)"</span><br><span> )</span><br><span> return messageSet</span><br><span> }</span><br><br><span> def query = buildJiraQuery(quarterText as Integer)</span><br><span> searchService.validateQuery(user, query)</span><br><span> }</span><br><br><span> @Override</span><br><span> Query getQuery(QueryCreationContext queryCreationContext, FunctionOperand operand, TerminalClause terminalClause) {</span><br><span> def quarter = operand.args.first() as Integer</span><br><span> def query = buildJiraQuery(quarter)</span><br><br><span> luceneQueryBuilder.createLuceneQuery(queryCreationContext, query.whereClause)</span><br><span> }</span><br><br><span> private com.atlassian.query.Query buildJiraQuery(Integer quarter) {</span><br><span> int year = LocalDate.now().year</span><br><br><span> LocalDate startDate</span><br><span> LocalDate endDate</span><br><br><span> switch (quarter) {</span><br><span> case 1:</span><br><span> startDate = LocalDate.of(year, 1, 1)</span><br><span> endDate = LocalDate.of(year, 4, 1)</span><br><span> break</span><br><span> case 2:</span><br><span> startDate = LocalDate.of(year, 4, 1)</span><br><span> endDate = LocalDate.of(year, 7, 1)</span><br><span> break</span><br><span> case 3:</span><br><span> startDate = LocalDate.of(year, 7, 1)</span><br><span> endDate = LocalDate.of(year, 10, 1)</span><br><span> break</span><br><span> case 4:</span><br><span> startDate = LocalDate.of(year, 10, 1)</span><br><span> endDate = LocalDate.of(year + 1, 1, 1)</span><br><span> break</span><br><span> default:</span><br><span> throw new IllegalArgumentException("Quarter must be 1, 2, 3, or 4")</span><br><span> }</span><br><br><span> def jql = "created >= '${startDate}' AND created < '${endDate}'"</span><br><span> queryParser.parseQuery(jql)</span><br><span> }</span><br><span>}</span>